Marketplace Project: Starting with the Marketplace
Learning Objectives
- You can establish a relational marketplace through reversible dbmate migrations.
- You can carry seller and category relationships through SQL, API JSON, and browser rendering.
- You can write regression tests and verify the cumulative marketplace project across its boundaries.
We have followed a stored todo through the API and into the browser. Now you will use that same path to build the first version of a campus marketplace. Each listing belongs to a seller and a category, so we will need to carry those relationships from the database to the page. This first version is a local, read-only application with synthetic development records. Forms, authentication, and auctions come later.
You will build the cumulative marketplace project in a local marketplace repository that is separate from the practice application. The first card provides the course-managed Git repository and explains how to clone it into marketplace/. Use that same local marketplace repository for these six milestones and all later marketplace milestones. Each handout contains the complete requirements, local checks, and submission instructions for its increment. Submit the marketplace project by committing and pushing from the marketplace repository.
Later cards emphasize continuing in the same marketplace repository. They also offer a reference branch containing an instructor example through the previous milestone, available after that milestone passes. The handouts explain how to inspect it without replacing your work. A newly cloned copy of your marketplace repository instead retrieves your own pushed commits; it is not a sample solution.
Database foundation
Start with the data: the marketplace needs a schema and related example records before we can show any listings. Use dbmate to check that your first change can be applied, rolled back, and reapplied while preserving the neutral baseline.
Marketplace milestone 1: database foundation
0 / 60 points
Objective and reference
Establish a reproducible database foundation for a campus marketplace. In this milestone, add users, hierarchical categories, listings, and synthetic development records to the supplied marketplace repository.
The reversible todo migration in PostgreSQL, Migrations & Development
Data is the worked example for this exercise. Parent rows must exist before
rows that reference them. INSERT ... SELECT can retrieve an identity by a
stable email address or slug. This milestone does not require authentication,
forms, auctions, or other marketplace features.
Clone the marketplace repository
This card provides a course repository already populated with the walking skeleton.
- From the practice application (
practice/), rundocker compose downto free ports 5173 and 8000. An ordinary shutdown preserves its database. - Use this card’s Copy clone command button.
- From the parent directory, paste the complete command, append
marketplaceto choose the destination folder, and run it. - Enter and start the marketplace repository:
cd marketplacegit statusdocker compose up --build- Confirm that the counter and Load todos work at
http://localhost:5173before adding marketplace code.
Keep this marketplace repository for every marketplace milestone and keep the
practice application for neutral experiments. If you already cloned the
course-managed Git repository, continue in your existing marketplace repository.
Do not extract a ZIP or run git init.
Use a distinct Compose project name for each copy. Do not override the names
with a shared COMPOSE_PROJECT_NAME. The committed project.env supplies
disposable local database settings.
Add a migration file and create tables
Keep the supplied database-migrations/001_create_todos.sql byte-for-byte
unchanged. Create database-migrations/002_marketplace.sql.
The new dbmate migration must contain exactly one plain -- migrate:up
marker followed by exactly one plain -- migrate:down marker.
In the up section, create these tables with exactly the columns described below. Do not add other columns.
users: an always-generated integer identityidprimary key; required, unique textemail; required textdisplay_name; and optionalTIMESTAMPTZdeleted_at;categories: an always-generated integer identityidprimary key; optional integerparent_idreferencingcategories(id)with an explicitON DELETE RESTRICT; required textname; and required, unique textslug;listings: an always-generated integer identityidprimary key; required integerseller_idreferencingusers(id)andcategory_idreferencingcategories(id), with an explicitON DELETE RESTRICTon both foreign keys; required texttitle; required textdescriptiondefaulting to an empty string; and required integerstarting_priceconstrained to be nonnegative.
In the down section, drop only listings, categories, and users, in that
dependency-safe order. Leave the neutral todos baseline intact.
Add data
Insert the following records in dependency-safe order:
- Users Jamie (
jamie@example.test) and Noor (noor@example.test). - Root categories Electronics (
electronics) and Books (books). - Computers (
computers) as a child of Electronics. - These three listings:
| Seller | Title | Category | Description | starting_price |
|---|---|---|---|---|
| Jamie | USB-C dock | Computers | Dock with a power adapter. | 1500 |
| Noor | Discrete Mathematics textbook | Books | Used textbook with notes. | 800 |
| Jamie | Desk lamp | Electronics | Small adjustable lamp. | 500 |
starting_price stores integer euro cents: 1500 means €15.00.
Resolve relationships from stable email addresses and slugs rather than assuming generated IDs. Milestone 1 assesses the resulting relationships; milestone 4 advances the identities before automatically testing these stable lookups.
Test
First, apply the migration in the marketplace repository:
docker compose run --rm database-migrationsUse a separate disposable Compose project for the complete up/down/up check.
Replace wsd-marketplace-check with an unused name if a Compose project with that
name already contains work you need. Use the same name for every command in
the check.
1. Apply and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrationsdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonAt the psql prompt, inspect the tables and the seller/category relationships:
\dtSELECT listings.title, users.email, categories.slug, listings.starting_priceFROM listingsJOIN users ON users.id = listings.seller_idJOIN categories ON categories.id = listings.category_idORDER BY listings.title;SELECT child.slug, parent.slug AS parent_slugFROM categories AS childJOIN categories AS parent ON parent.id = child.parent_id;\qVerify that there are two users, three categories, and three listings, and that Computers is a child of Electronics.
2. Roll back and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrations --no-dump-schema rollbackdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonAt the psql prompt, run \dt and SELECT * FROM todos;, then exit with
\q. The marketplace tables must be absent and the original todo must remain.
3. Reapply and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrationsdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonRepeat the inspection from step 1, then exit with \q. Reapplication must
recreate the same records without duplicates. dbmate’s status command can
also show the applied versions.
4. Remove the disposable Compose test project.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml downThis final command discards only the temporary test database.
Submit
In the marketplace repository, stage the new migration, inspect it, commit, and push:
git add database-migrations/002_marketplace.sqlgit diff --cachedgit commit -m "Add marketplace database foundation"git push origin masterPush the marketplace project, including its supplied files. No hosted account or public URL is required. An unchanged marketplace repository is not a completed foundation submission.
The grader awards:
- 40 points for the schema, constraints, relationships, and seed data;
- 10 points for rolling back while preserving the migration 001 baseline; and
- 10 points for correctly reapplying the migration.
Relational read API
With the records in place, the next step is to make them available through GET /api/listings and GET /api/categories. Each listing’s response carries its seller and actual category, using consistent public field names and price units. The /api prefix distinguishes these data endpoints from browser page routes introduced later.
Marketplace milestone 2: relational read API
0 / 50 points
Continue the marketplace project
After milestone 1 passes, continue in your marketplace repository. There is no new marketplace repository for this milestone. Run:
git fetch originThis prepares the milestone for grading and makes its reference available
without changing your files. Keep working on master.
The recovery command creates a fresh local marketplace repository from your
own pushed master history in the course-managed remote Git repository. It cannot recover uncommitted changes or
commits that you have not pushed.
Objective and reference
Expose the stored marketplace relationships through two database-backed read endpoints:
GET /api/listingsGET /api/categories
Use the route/repository separation in Tracing a Request as your model.
Keep SQL in repository modules and request handling in api/src/app.ts.
Preserve the existing /health and /api/todos routes. Keep connection
shutdown in app-run.ts; do not call sql.end() in a route or repository.
Add the repository modules
Create these files at the exact paths shown:
api/src/listingRepository.tsapi/src/categoryRepository.ts
Both files are part of the submitted contract. In each file:
- import the shared
sqlclient from./database.ts; - export a type-correct
const findAllfunction callable without arguments; and - order rows by ascending stored ID and return at most 100 rows.
The listings query must obtain seller and actual category names through the stored foreign-key relationships. Each returned row has exactly these fields:
| Field | JSON type | Source |
|---|---|---|
id | number | stored listing ID |
title | string | stored title |
description | string | stored description |
startingPrice | number | stored integer euro cents |
sellerId | number | stored seller ID |
categoryId | number | stored category ID |
sellerName | string | related user’s display name |
categoryName | string | related category’s name |
Do not expose email or return any additional fields. Do not hardcode names, synthesize replacements, or infer relationships from row positions. A listing belongs to its actual category, not that category’s parent. For example, the USB-C dock belongs to Jamie and Computers, not Electronics.
Each category row has exactly id, parentId, name, and slug. Return
parentId as a number for a child and null for a root.
Use quoted SQL aliases to preserve camel-case JSON names, for example:
l.starting_price AS "startingPrice"The contracts must continue to work when the database contains more than the original seed rows and when those rows have different relationships.
Add the routes
In api/src/app.ts:
- Import the two
findAllfunctions under distinct names, such asfindAllListingsandfindAllCategories. - Add
GET /api/listingsandGET /api/categories. - Await the appropriate repository query in each route.
- Return its result as JSON with status 200.
Test
After the API watcher restarts, open:
http://localhost:8000/api/listingshttp://localhost:8000/api/categories
Check the field names, numeric types, row order, seller relationships,
category relationships, and root/child parentId values. A successful
/health response alone does not exercise the database queries.
Run the supplied API tests in the separate Compose test project using the README commands. With host Deno, you can instead run:
deno task test:apiSubmit
Stage the two new repositories and the changed application module, inspect the staged diff, commit, and push from the same marketplace repository:
git add api/src/listingRepository.ts api/src/categoryRepository.ts api/src/app.tsgit diff --cachedgit commit -m "Add marketplace read API"git push origin masterSubmit the marketplace project, including the migrations from milestone 1. The grader awards:
- 5 points for type correctness and the required API-module exports;
- 5 points for the listing response contract;
- 15 points for varied seller and category relationships;
- 10 points for public values and integer-cent prices;
- 10 points for the category response contract; and
- 5 points for deterministic ordering and the 100-row limits.
Type correctness is assessed only by the 5-point API-module check. Its compiler diagnostics appear in that test result. A type error does not block the other 45 points: the grader runs API behavior tests independently when the code can execute.
Browser marketplace read
Now bring the listings into the browser. Add a component that requests data when the user activates it and displays the returned relationships and prices, while keeping the original counter and todo interactions working.
Marketplace milestone 3: browser marketplace read
0 / 50 points
Continue the marketplace project
After milestone 2 passes, continue in your marketplace repository. There is no new marketplace repository for this milestone. Run:
git fetch originThis prepares the milestone for grading and makes its reference available
without changing your files. Keep working on master.
The recovery command creates a fresh local marketplace repository from your
own pushed master history in the course-managed remote Git repository. It cannot recover uncommitted changes or
commits that you have not pushed.
Objective and reference
Display the related listing data from GET /api/listings in the browser.
Follow the request pattern used by the supplied TodoList.svelte component
in Tracing a Request.
Create client/src/lib/ListingList.svelte and update
client/src/routes/+page.svelte. Both files are part of the submitted
contract.
Empty, error, and retry-state design is developed in Part 2. This milestone assesses the initial, pending, and successful nonempty states.
Create the listing component
In client/src/lib/ListingList.svelte, add a Load listings button and an
asynchronous const loading function.
The request behavior must meet this contract:
- Do not request listings on initial render.
- Make one
GET /api/listingsrequest each time the user activates the button. - Build the URL using
import.meta.env.VITE_API_BASE_URL; do not hardcode a host or port. - Display the exact text
Listings: not loadedinitially. - Display the exact text
Listings: loadingwhile the request is pending. - Display the exact text
Listings: loadedafter a successful, nonempty response. - Put the status text in a polite live region.
Render the returned listings as a keyed list. Each listing must be a list item containing:
- its title as a heading;
- its seller name after the visible label
Seller:; - its actual category name after the visible label
Category:; and - its starting price after the visible label
Starting price:.
Convert integer euro cents to euros with two decimal places. For example,
1500 must appear as Starting price: €15.00.
Render the values returned by the API, including varied titles, names,
categories, and prices. Do not hardcode the seed records. A local Listing
type can describe numeric id and startingPrice fields and string title,
sellerName, and categoryName fields.
Update the page
In client/src/routes/+page.svelte:
- Change both the level-one heading and document title to
Campus Marketplace. - Import the new component through
#lib/ListingList.svelte. - Render it in a page section exposed as an accessible region with the exact
name
Listings. For example, give the section aListingsheading and connect the section to that heading witharia-labelledby.
Place the Load listings button, rendered listing items, and exactly one
polite listing-status element inside the Listings region.
Preserve the supplied Counter.svelte and TodoList.svelte components and
their page sections. The todo section must keep the accessible region name
Todos, and the original Load todos and counter interactions must still
work.
Keep the current SvelteKit 3 scaffold and #lib import mapping. Do not
replace the supplied framework configuration or dependency pins.
Test
Check the page locally:
- Confirm the initial status appears before any listing request.
- Activate Load listings and inspect the request and pending status.
- Compare the visible titles, seller names, category names, and formatted prices with the API response.
- Confirm that Load todos and the counter still work.
Run the component and browser suites using the README’s isolated test commands. Then verify the production build:
docker compose run --build --rm --no-deps client deno task buildSubmit
Stage the new component and changed page, inspect the staged diff, commit, and push:
git add client/src/lib/ListingList.svelte client/src/routes/+page.sveltegit diff --cachedgit commit -m "Add marketplace listing view"git push origin masterSubmit the marketplace project. The grader builds client/src/** with the
course’s pinned scaffold and supplies varied API responses. It awards:
- 5 points for the production build;
- 5 points for the page heading and document title;
- 10 points for the explicit load action;
- 25 points for rendered titles, relationships, and prices; and
- 5 points for preserving the todo and counter interactions.
Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.
Varied reproducible data
Let’s give the application more varied records to work with. Add another reversible migration with different seller/category combinations. Its rollback must remove only its own additions, so use stable record values rather than assumed generated identifiers.
Marketplace milestone 4: varied reproducible data
0 / 40 points
Continue the marketplace project
After milestone 3 passes, continue in your marketplace repository. There is no new marketplace repository for this milestone. Run:
git fetch originThis prepares the milestone for grading and makes its reference available
without changing your files. Keep working on master.
The recovery command creates a fresh local marketplace repository from your
own pushed master history in the course-managed remote Git repository. It cannot recover uncommitted changes or
commits that you have not pushed.
Objective and reference
Add varied development records that reveal whether the API and browser page continue to work with additional relationships.
Use the reversible migration in PostgreSQL, Migrations & Development Data as your model. Resolve relationships through stable values in both migration directions. Existing rows may have generated IDs that are neither small nor consecutive.
Create the migration
Create this file:
database-migrations/003_more_development_data.sqlTreat migrations 001 and 002 as shared, already-applied history. Preserve
both files and put all new work in migration 003. Use exactly one plain
-- migrate:up marker followed by one plain -- migrate:down marker, and use
dbmate’s default transaction.
Migration 003 only adds and removes its own development records. Do not
alter the existing table structure, constraints, or rows during migration-up
or migration-down.
The grader-reserved-m4- and [grader-reserved-m4] prefixes belong to hidden
fixture data. Do not use either prefix in your migration.
Add varied data
In the up section, add all of the following:
- one distinct synthetic user with a nonempty email and display name;
- one distinct, named child category beneath Electronics, Books, or Computers, with a nonempty name and slug; and
- exactly three distinct listings with nonempty titles.
The three listings must span at least two distinct (seller, category) pairs.
At least one listing must use the new user, and at least one listing must use
the new category. These can be different listings. Give every listing a
nonnegative integer starting_price in euro cents.
Choose stable, migration-specific values for the new user’s email, the new category’s slug, and all three listing titles. Resolve the user and category relationships from stable emails and slugs rather than assumed generated IDs.
Add the rollback
In the down section:
- Remove exactly the three listings owned by migration
003. - Remove the category owned by migration
003. - Remove the user owned by migration
003.
Use stable values to identify those rows. Preserve every milestone 1 row and all other pre-existing or independently added data. Never clear an entire table to undo this migration.
Test
Test the complete migration chain in a separate disposable Compose project.
If wsd-marketplace-check is already protecting work you need, replace it
with an unused name and use that same name throughout.
1. Apply and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrationsdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonAt the first psql prompt, inspect the new user, category, listings, and
their relationships. For example:
SELECT listings.title, users.email, categories.slugFROM listingsJOIN users ON users.id = listings.seller_idJOIN categories ON categories.id = listings.category_idORDER BY listings.title;\q2. Roll back and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrations --no-dump-schema rollbackdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonRepeat the joined query and verify that only the migration 003 additions
disappeared. The milestone 1 rows and all other existing data must remain.
Exit with \q.
3. Reapply and inspect.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml run --rm database-migrationsdocker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml exec database psql -U walking_skeleton -d walking_skeletonVerify that reapplication restores the same email, slug, titles, and
relationships without relying on the original generated IDs. Exit with \q.
4. Remove the disposable project.
docker compose -p wsd-marketplace-check -f compose.yaml -f compose.test.yaml downThis discards only the temporary test database.
Apply migration 003 to the normal development database without resetting
it, then inspect the SQL data, API output, and browser page:
docker compose run --rm database-migrationsSubmit
The grader records the new email, slug, and titles during the first application and requires those same stable values after rollback and reapplication.
Stage the new migration, inspect the staged diff, commit, and push:
git add database-migrations/003_more_development_data.sqlgit diff --cachedgit commit -m "Add varied marketplace development data"git push origin masterSubmit the marketplace project. The grader awards:
- 20 points for the new related data over advanced identity values;
- 10 points for removing only migration
003data during rollback; and - 10 points for stable reapplication and coherent migration state.
Test the API relationship
First, protect the relationship where the API returns it. Write a test that distinguishes a listing’s actual category from another category. You can check this boundary without opening a browser, and use a deliberately faulty response to see whether the assertion notices the difference.
Marketplace milestone 5: API relationship regression test
0 / 25 points
Continue the marketplace project
After milestone 4 passes, continue in your marketplace repository. There is no new marketplace repository for this milestone. Run:
git fetch originThis prepares the milestone for grading and makes its reference available
without changing your files. Keep working on master.
The recovery command creates a fresh local marketplace repository from your own pushed master history. It
cannot recover uncommitted changes or commits that you have not pushed.
Objective and reference
Add a Deno regression test that proves listings retain their actual category relationships. Create it at this exact path in the marketplace repository:
api/tests/student_category_test.tsThis milestone assesses the test as regression evidence: it must pass against a compatible correct API and fail against APIs with incorrect relationships.
Write the regression test
Import and use:
- assertions from
@std/assert; appfrom@src/app.ts; andsqlfrom@src/database.ts.
Request GET /api/listings, assert status 200, find these records by title,
and assert their actual categories:
- USB-C dock: category Computers;
- Discrete Mathematics textbook: category Books.
Assert both category values. Seller assertions for Jamie and Noor provide useful additional evidence but are not required for these points.
A compatible API may return additional listings in a different stored order. Therefore:
- find the two records by title;
- do not rely on array positions, generated IDs, or an exact row count; and
- make the test reject both a constant category and categories attached to the wrong titles.
Keep the shared SQL client open for every awaited test step and close it once
in finally. Keep the required test self-contained; additional helper modules
are outside the returned-test contract.
Starting structure
You may begin with this structure:
import { assertEquals } from "@std/assert";import { app } from "@src/app.ts";import { sql } from "@src/database.ts";
Deno.test("listings preserve their category relationships", async (t) => { try { await sql`SELECT 1`; await t.step("the dock has its expected relationships", async () => { const response = await app.request("/api/listings"); // TODO: check the status, find the dock, and assert its category. throw new Error("Complete the dock assertions"); }); await t.step("the textbook has different relationships", async () => { const response = await app.request("/api/listings"); // TODO: check the status, find the textbook, and assert its category. throw new Error("Complete the textbook assertions"); }); } finally { await sql.end(); }});Replace the TODO comments and deliberate throw statements with meaningful
assertions.
Test
From the marketplace repository root, run the test against an isolated test database.
If wsd-marketplace-api-test is already protecting work you need, replace it
with an unused name and use that same name for cleanup.
docker compose -p wsd-marketplace-api-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test tests/student_category_test.tsdocker compose -p wsd-marketplace-api-test -f compose.yaml -f compose.test.yaml downThe test must pass against the correct API and fail when every listing is reported with the same category or when the two known categories are exchanged. A timeout, crash, empty suite, skipped-only suite, or assertion that always succeeds is not regression evidence.
Submit
Stage the new test, inspect it, commit, and push the marketplace project from the same marketplace repository:
git add api/tests/student_category_test.tsgit diff --cachedgit commit -m "Add listing relationship API regression test"git push origin masterThe grader uses pinned course dependencies and the complete cumulative project, but this milestone scores only the returned API test. It awards:
- 5 points when the test passes against a compatible correct API; and
- 20 points when it rejects incorrect title-to-category relationships.
Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.
Test the browser and complete the application
Now follow the same relationship into the page. Add a browser regression test and submit the complete application. The final milestone checks both whether the browser test detects defects and whether a real request reaches the database and returns data to the page from a fresh start. Your accepted API test and the earlier application features remain prerequisites; they do not earn their points a second time.
Marketplace milestone 6: browser regression and Part 1 acceptance
0 / 45 points
Continue the marketplace project
After milestone 5 passes, continue in your marketplace repository. There is no new marketplace repository for this milestone. Run:
git fetch originThis prepares the final Part 1 milestone for grading and makes its reference
available without changing your files. Keep working on master.
The recovery command creates a fresh local marketplace repository from your own pushed master history. It
cannot recover uncommitted changes or commits that you have not pushed.
Objective and reference
Add a Playwright regression test for the browser listing flow, then submit the cumulative marketplace project for Part 1 acceptance. Create the test at this exact path:
e2e-tests/tests/student_listing.spec.tsThis milestone assesses both your returned browser test and the cumulative data flow from a fresh database through the API to the browser.
Empty, error, and retry-state design is developed and assessed in Part 2 and is not required here.
Write the browser regression test
Import from @playwright/test and use the configured base URL. In the test:
- Navigate to
/. - Activate Load listings.
- Locate the USB-C dock and Discrete Mathematics textbook by their headings.
- Within each listing item, assert these visible labels:
- USB-C dock:
Seller: JamieandCategory: Computers; - Discrete Mathematics textbook:
Seller: NoorandCategory: Books.
Use waiting, web-first assertions. Do not hardcode a development host or port, and do not merely search for the four values somewhere on the page. Scope the seller and category assertions to the corresponding listing item.
Compatible fixtures may include other listings in a different order. Find the two named items instead of assuming positions or an exact list length. The test must reject:
- a missing Load listings action;
- a seller or category value taken from the other named listing;
- any incorrect seller/category relationship for either named listing; and
- one constant category reported for every listing.
Keep the visible labels themselves as Seller: and Category:. A swap defect
assigns relationship values to the wrong listing; it does not exchange the two
label words.
Starting structure
You may begin with this structure:
import { expect, test } from "@playwright/test";
test("loading listings displays their relationships", async ({ page }) => { await page.goto("/"); // TODO: activate Load listings. // TODO: locate each listing item and assert its labelled values. throw new Error("Complete the browser assertions");});Replace the TODO comments and deliberate throw with meaningful locators and
assertions.
Preserve the cumulative application
The pushed project must still support the complete Part 1 flow:
- a fresh database applies migrations
001through003and reconstructs the marketplace schema and data; /health,/api/todos,/api/listings, and/api/categorieswork;- the client produces a production build;
- the original counter and todo read still work; and
- the marketplace list renders each title, seller, actual category, and integer-cent price formatted as euros.
Keep the API relationship test from milestone 5. Every path listed under Required files on this card must exist in the pushed cumulative tree. A structurally incomplete tree is rejected before individual checks begin.
The grader uses canonical pinned dependencies and configuration. It does not execute submitted Docker, Compose, or package scripts.
Test
Run the browser test with an isolated Compose project. The first command
starts a fresh database, applies the migrations, builds the application, and
then runs Playwright. If wsd-marketplace-browser-test is already protecting
work you need, replace it with an unused name and use the same name for every
command, including cleanup.
docker compose -p wsd-marketplace-browser-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests npx playwright test tests/student_listing.spec.tsdocker compose -p wsd-marketplace-browser-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task testdocker compose -p wsd-marketplace-browser-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task builddocker compose -p wsd-marketplace-browser-test -f compose.yaml -f compose.test.yaml downThe first command checks your returned browser evidence through the real local
stack. The component suite checks the preserved counter and todo components;
the build command checks the cumulative client artifact. Browser traces from
failures appear in e2e-tests/test-results/.
Submit
Stage the new browser test and any cumulative corrections. Inspect the staged changes, commit, and push from the same marketplace repository:
git add e2e-tests/tests/student_listing.spec.tsgit add PATHS_YOU_CORRECTEDgit diff --cachedgit commit -m "Add marketplace browser regression test"git push origin masterOmit the second git add command when no application correction was needed.
Replace PATHS_YOU_CORRECTED with explicit paths rather than staging build or
test output.
The grader awards 30 points for the returned browser test:
- 5 points for passing against the compatible reference;
- 5 points for detecting a missing load action;
- 10 points for detecting seller/category values assigned to the wrong named listing or another incorrect relationship in either named listing; and
- 10 points for detecting a constant category.
A further 15 points require the browser to display the correctly related sellers, categories, and formatted prices through the submitted API and a fresh database. The migration, API, original-component, and build checks are readiness gates for that flow. They identify the blocking layer but do not award separate points.
Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.
For now, the marketplace establishes a successful read from storage to the browser. Part 2 develops the listing view further: it distinguishes empty collections and failed requests, clears stale rows, and supports recovery after a failure. You do not need to add those later interaction states to finish Part 1.
Once these milestones are complete, you have a first marketplace that connects related records to a browser view, along with tests to help you keep it working. Keep the marketplace repository after Part 1 acceptance; you will continue the marketplace project there in Part 2.
Check Your Understanding
- How does a listing remain connected to its seller and category from the database to the browser?
- Why should development examples include more than one seller/category combination?
- What must a migration’s down section preserve when it removes that migration’s additions?
- How do API tests and browser tests help check different parts of the marketplace?
- Why does each submission contain the cumulative marketplace project rather than only the newest files?