Skip to main content

Homework 01

Expected Workload

For a student who has kept up with the lecture material and is reasonably comfortable with Docker, Express, Redis, and basic HTML forms, this homework should take about 6 to 9 hours to complete carefully.

That estimate assumes you are not learning every tool from scratch during this assignment. It includes time to build the system, test the full flow, capture evidence, and write a clear brief.md.

A reasonable breakdown is:

  • 1 to 1.5 hours to set up the multi-container project structure, Dockerfiles, and compose.yml
  • 1 to 1.5 hours to build the API routes and basic Redis-backed order state
  • 0.75 to 1.25 hours to build the worker and simulate asynchronous processing
  • 0.75 to 1.25 hours to build the kiosk page and monitoring dashboard with simple server-rendered HTML
  • 1 to 1.5 hours to build the kiosk-sim service and make its behavior configurable
  • 0.75 to 1 hour to add and verify idempotency behavior for duplicate logical orders
  • 0.5 to 1 hour to test the system end to end, collect screenshots or short videos, and finish brief.md

The most reliable way to complete this assignment successfully is to treat it as a sequence of small milestones instead of one long build session. In practice, students usually lose the most time when they wait too long to start, try to build every part at once, or postpone testing and documentation until the end.

A good approach is to time-block this work on your calendar in advance. Reserve a few focused work sessions, decide what each session should accomplish before you begin, and stop each session with the project in a runnable state. That makes it much easier to recover if you get stuck and much less likely that you will run out of time near the deadline.

One reasonable schedule is:

  • Session 1: 1.5 to 2 hours for project setup, Dockerfiles, Compose, and a minimal API that starts correctly
  • Session 2: 1.5 to 2 hours for Redis-backed order handling, queueing, and a worker that processes jobs
  • Session 3: 1.5 to 2 hours for the kiosk page, monitoring dashboard, and basic end-to-end browser flow
  • Session 4: 1.5 to 2 hours for the kiosk-sim service, duplicate-request handling, testing, evidence capture, and finishing brief.md

If you prefer shorter sessions, split the work across more calendar blocks, but still assign each block a concrete goal. The key habit is to schedule the time intentionally rather than hoping you will "find time later."

You should approach this homework like a small delivery sprint: define milestones, implement incrementally, test continuously, and finish with clear deliverables.

Reliable Campus Kiosk Simulation

In this homework, you will build a small live system that simulates a real system that does the following:

  • a kiosk page where a user places an order
  • a background worker that processes the order later
  • a kiosk simulator service that can behave like many kiosks submitting orders in parallel
  • a monitoring dashboard that shows what is happening inside the system
  • a duplicate-protection rule so the same order is not completed twice

This assignment is meant to help you learn how to simulate a system using the concepts and techniques from this course in a way that still feels practical, visual, and engaging. When you finish, you should be able to open your app, click around, watch orders move through the system, and explain how your simulation reflects course ideas such as coordination, state changes, and safety under retries.

This is also practice for the larger simulation project later in the course. Here, you are building one small slice well instead of building a huge system.

Key Learning Outcomes

By the end of this homework, you should be able to:

  • Build and run a small multi-container web system with Docker and Docker Compose
  • Create an Express application that serves both API routes and simple server-rendered HTML pages
  • Use Redis as shared infrastructure for queueing work and storing system state
  • separate fast request handling from slower background work with a worker process
  • Simulate concurrent clients with a separate kiosk-sim service
  • Design a simple operator view that makes system behavior easy to observe
  • Explain and implement idempotency so duplicate requests do not create duplicate completed work
  • Document a small distributed scalable system clearly enough that another person can run and verify it

Scenario

Imagine that your team was asked to build the software for a self-serve campus snack kiosk.

Students walk up to a kiosk screen, place orders, and expect a quick response. Behind the scenes, the real work should happen in the background. At the same time, a staff member or developer should be able to open a monitoring dashboard and watch orders move through the system.

Your simulation should have two different feelings:

  • the kiosk page should feel like the customer view
  • the monitoring dashboard should feel like the control room

That contrast is part of what makes this assignment interesting.

The important correctness rule is this:

If the same logical order is submitted more than once, your system must not create duplicate completed work.

That rule is the idempotency part of the assignment. In simple terms: retries are okay, duplicate completed side effects are not.

You may enforce idempotency at the API boundary, in the worker, or in both places, but your write-up must clearly explain why your system does not complete the same logical order twice.

What You Are Building

You are building one small web system with four running parts:

  1. api
    • an Express server
    • renders the kiosk page and monitoring dashboard
    • accepts order requests
    • stores and returns order state
  2. worker
    • runs separately from the API
    • pulls queued work from Redis
    • simulates preparing the order
  3. kiosk-sim
    • runs separately from the API
    • simulates N kiosks sending orders in parallel
    • helps you demonstrate concurrent submissions and retry behavior
  4. redis
    • holds queue data and shared order state

Use Docker and Docker Compose so the whole system starts together.

For example, it is reasonable to expose the main app on http://localhost:3000 during local development so a grader can open the kiosk page, the monitoring dashboard, and API routes from the same base URL.

When the system is working well, this should happen:

  1. A user opens the kiosk page.
  2. They submit an order.
  3. The page updates quickly.
  4. The worker processes the job in the background.
  5. The kiosk simulator service can generate many kiosk requests in parallel.
  6. The monitoring dashboard shows the order move from queued to processing to completed.
  7. If the same logical order is retried, the system does not complete it a second time.

Assignment Requirements

Your submission must include all of the following:

  1. A Dockerized multi-service system with these services:
    • api
    • worker
    • kiosk-sim
    • redis
  2. An Express API container.
  3. A worker container that processes queued jobs asynchronously.
  4. A kiosk simulator container that can simulate N kiosks placing orders in parallel.
  5. Redis used as part of the running design, not just as an optional extra.
  6. A basic HTML kiosk simulator page for submitting orders.
  7. A basic HTML monitoring dashboard for observing system state.
  8. A docker compose up --build workflow that starts the system.

Constraints

  • Use Node.js and Express for the API. Other programming languages are also allowed; see below.
  • Build a basic server-rendered UI using plain HTML.
  • Use Redis for queueing and shared state.
  • Simulate kiosk fulfillment with a short delay so the queue boundary is visible.
  • Support a configurable kiosk load generator through the kiosk-sim service.
  • Document exact setup, run, test, and cleanup commands.
  • Keep the scope small and focused. One queue and one worker process is enough.

Programming Languages

The course shows examples primarily in TypeScript and JavaScript, and those are the recommended languages for this assignment.

You are welcome to use another language if you prefer. However, if you do, recognize that you may need to explain more in your submission because your audience may not already be familiar with that language, its tooling, or any libraries you choose.

If you use a non-recommended language, your write-up should make it easy for the course staff to understand how to run your project, what each major dependency does, and how your implementation maps to the concepts from the course.

What Success Looks Like

A strong submission is not the one with the fanciest design. A strong submission is the one that is easy to run and easy to understand.

Your project should make a grader think:

  • "I can start this with one compose command."
  • "I can place an order from the kiosk page."
  • "I can watch the worker handle the order."
  • "I can run the kiosk simulator and see parallel kiosk traffic hit the system."
  • "I can see the monitor update."
  • "I can retry the same order and the system stays correct."

That is the standard you should aim for.

Required API Contract

Your API must implement at least these routes.

You may add more routes for HTML pages, redirects, dashboards, or helper actions.

POST /orders

Accept a new logical order request.

This route may accept either JSON or standard HTML form submissions, as long as the same logical fields are provided and the server handles them consistently.

Required request data:

  • A stable client-supplied logical order identifier such as clientOrderId
  • An item name
  • A quantity

About the identifier:

  • This identifier must be created by the client, not by the API
  • The same logical order must reuse the same clientOrderId on retries
  • Different kiosks should avoid collisions by including a kiosk identifier in the value
  • A simple pattern such as kiosk-03-00042 is enough

You may also create a separate server-side orderId internally if you want, but that is optional and it is not the identifier used for idempotency.

If you build the kiosk page as a normal HTML form, a simple approach is to submit the form to a server route that reads form fields, including a visible clientOrderId, and then applies the same order-handling logic on the server side.

Suggested JSON body:

{
"clientOrderId": "kiosk-01-0001",
"item": "iced-latte",
"quantity": 2,
"customer": "Ava"
}

Required behavior:

  • Validate required fields
  • Store or reuse the stable logical identifier
  • Enqueue work for a first-time request
  • Return quickly instead of doing fulfillment inline
  • If the same logical order is submitted again, return a non-error response and do not create duplicate work

Expected status codes:

  • 202 Accepted for a newly accepted order
  • 200 OK for a recognized duplicate submission that reuses existing order state
  • 400 Bad Request for invalid input

GET /orders/:clientOrderId

Return the current state of an order.

Expected behavior:

  • Return 404 if the order is unknown
  • Return 200 with enough state to see whether the order is queued, processing, or completed

Suggested response shape:

{
"clientOrderId": "kiosk-01-0001",
"status": "completed",
"item": "iced-latte",
"quantity": 2,
"duplicate": false
}

You may include additional fields such as timestamps, attempt counts, or worker notes if they help demonstrate your design.

Required UI Contract

Your project must expose at least two user-facing pages:

Kiosk Page

This page should let a user submit an order through a standard HTML form.

Required behavior:

  • Support successful order submission through the browser
  • Show whether the request was accepted or recognized as a duplicate
  • Make the client-generated order identifier visible so the order can be tracked
  • Make it possible to re-submit a previously used clientOrderId so a grader can intentionally demonstrate duplicate handling

Recommended browser behavior:

  • When preparing a brand-new logical order, the page should generate a fresh clientOrderId
  • The generated ID should include the kiosk identifier if your system models multiple kiosks
  • After submission, the page should continue to show the last submitted clientOrderId
  • A grader should be able to copy, reuse, or edit that same clientOrderId

One simple approach is to keep the clientOrderId in a visible editable form field. The page can pre-fill a new value for a fresh order, but the grader should still be able to leave it unchanged to simulate a retry or change it manually to inject a specific duplicate into the system.

Monitoring Dashboard

This page should let a user observe the simulation as it runs.

Required behavior:

  • Show recent orders or current order state
  • Show enough information to distinguish queued, processing, and completed
  • Allow a grader to refresh or revisit the page and observe updated state

Recommended behavior:

  • Update often enough that a grader can visually watch orders move through the system
  • Use a simple refresh strategy instead of building a complex frontend
  • Keep the implementation understandable and easy to explain

You do not need live WebSockets or a complicated frontend framework for this page.

Simple reasonable options include:

  • a manual refresh button
  • a timed full-page reload every few seconds
  • server-rendered templates plus a browser auto-refresh

Any of those approaches is acceptable if it makes the state changes easy to see.

Another very simple option is to use a normal server-rendered monitoring dashboard and let the browser reload the whole page every few seconds. For example:

<script>
setTimeout(() => window.location.reload(), 3000)
</script>

or a meta refresh tag:

<meta
http-equiv="refresh"
content="3" />

That approach is perfectly acceptable for this assignment if it keeps the monitor easy to understand.

Choose the approach that best matches your implementation style. The goal is not sophistication. The goal is to make system changes visible with minimal complexity.

The UI can be plain. Styling is not the point here. Correct interaction and observability are.

If you want a good mental model:

  • The kiosk page is the "customer screen"
  • The monitoring dashboard is the "operator screen"

Both can be simple. What matters is that they clearly show the system working.

Required Kiosk Simulator Service

Your project must also include a separate service named kiosk-sim whose job is to simulate many kiosks sending orders to the API in parallel.

This service is not a browser UI. It is a small load-generation or event-generation service that helps demonstrate the distributed-system behavior of your design under concurrent request traffic.

Required Structure Under code/

Your code/ folder should include a dedicated kiosk-sim/ service directory. A recommended structure is:

code/
api/
kiosk-sim/
Dockerfile
simulator.js
redis/ (optional if customized)
worker/
compose.yml

You may organize filenames differently, but the service should have its own folder and its own Dockerfile. If your redis service uses the off-the-shelf Redis image from Docker Hub without any custom configuration, you do not need a separate code/redis/ folder.

What the kiosk-sim Container Should Do

At runtime, the service should:

  • start N independent kiosk loops or tasks
  • generate realistic order requests to the API
  • submit those requests concurrently rather than strictly one at a time
  • assign each kiosk a unique kiosk identifier
  • generate client-created IDs that include that kiosk identifier
  • randomly or at regular intervals send requests that intentionally reuse previously sent clientOrderId values to help demonstrate idempotency behavior
  • log enough information to make the simulated kiosk activity understandable

The service can run continuously, for a fixed number of rounds, or until stopped by Docker Compose. Choose a simple design and explain it clearly.

Dockerfile Expectations

The kiosk-sim/Dockerfile should be small and focused, similar in spirit to the API and worker images. It should:

  • install the dependencies needed to run the simulator
  • copy the simulator source files into the image
  • set a default command that starts the simulator process

For example, if you use Node.js, a simple Dockerfile could look like this:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "simulator.js"]

Compose Configuration and Environment Variables

Your compose.yml should define a kiosk-sim service and pass configuration through environment variables.

At minimum, support configuration for:

  • the number of kiosks to simulate, such as KIOSK_SIM_KIOSKS=5
  • the API base URL, such as KIOSK_SIM_API_BASE_URL=http://api:3000
  • a kiosk ID prefix, such as KIOSK_SIM_KIOSK_PREFIX=kiosk
  • the delay between submissions, such as KIOSK_SIM_INTERVAL_MS=1000

You may add more variables if they help your design. Useful optional examples include:

  • KIOSK_SIM_MAX_ORDERS_PER_KIOSK
  • KIOSK_SIM_RETRY_RATE
  • KIOSK_SIM_REUSE_EXISTING_ID_RATE
  • KIOSK_SIM_STARTUP_DELAY_MS
  • KIOSK_SIM_ITEMS

The goal is that it is easy to change the load pattern by editing compose.yml rather than editing source code. It is an important way to think about designing systems - the more toggles you provide to a component in your system, the easier it is to observe its behavior without changing the code.

What the Simulator Code Should Look Like

The implementation should be small and readable. A good design would usually include:

  1. Configuration loading from environment variables
  2. A helper that generates an order payload and stable clientOrderId
  3. A function that represents one kiosk's behavior
  4. A launcher that starts N kiosk tasks in parallel
  5. Logging that shows which kiosk sent which order and what response came back
  6. A retry path that can intentionally resend a previously used clientOrderId

A good ID strategy for the simulator is:

  • give each kiosk a unique kioskId, such as kiosk-01
  • let each kiosk maintain its own local counter
  • build IDs such as kiosk-01-0001, kiosk-01-0002, and so on

That approach makes two things clear:

  • different kiosks should not collide because their kiosk IDs differ
  • retries from the same kiosk can intentionally reuse the same clientOrderId

In pseudocode, the structure might look like this:

read env config
for kioskId in 1..N:
start async kiosk loop

kiosk loop:
while work remains:
choose new or reused clientOrderId
build order payload
POST /orders to api
optionally retry some logical orders with the same clientOrderId
sleep for configured delay

If you use JavaScript, a simple version could look like this:

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const sendOrder = async payload => {
const response = await fetch('http://api:3000/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})

// Check the response.
// Log useful information.
// Return parsed response data if you want.
}

const runKiosk = async kioskId => {
while (true) {
// Decide whether this kiosk should create a new clientOrderId
// or reuse a previous one to simulate a retry.
const payload = {
// Build a clientOrderId that includes the kioskId.
// Add item, quantity, customer, and any other fields.
}

await sendOrder(payload)
await sleep(1000)
}
}

const main = async () => {
const kioskIds = [
// Create one kiosk ID per simulated kiosk.
]
await Promise.all(kioskIds.map(kioskId => runKiosk(kioskId)))
}

main().catch(error => {
console.error(error)
process.exit(1)
})

That example is intentionally minimal. It shows the main ideas:

  • each kiosk gets its own kiosk ID
  • each kiosk creates its own clientOrderId values
  • retries can intentionally reuse the previous clientOrderId
  • all kiosks run in parallel with Promise.all

Your code does not need to be elaborate. The important thing is that it clearly simulates parallel kiosks and helps demonstrate the behavior of the rest of the system.

Required System Behavior

Your implementation must demonstrate all of the following:

  1. The API accepts work quickly and does not perform the simulated fulfillment inline.
  2. The worker processes queued orders asynchronously.
  3. The kiosk-sim service can simulate multiple kiosks placing orders in parallel.
  4. Redis stores enough information to make system state visible and understandable.
  5. The kiosk simulator page uses plain HTML form handling.
  6. The monitoring dashboard uses plain HTML and makes refreshed state easy to observe.
  7. Repeating the same logical order does not lead to duplicate completed effects.
  8. A grader can reproduce the behavior from documented commands and logs.

Idempotency Requirement

You must explicitly describe your idempotency strategy in the write-up.

For this assignment, idempotency means:

If the same logical order enters the system more than once with the same client-created identifier, the system should recognize that it is the same logical operation and avoid producing duplicate completed work.

This is why the client-generated ID matters so much.

If the browser or kiosk simulator sends:

  • clientOrderId = kiosk-01-0007

and then later sends the same clientOrderId again, your system should treat that as a retry or duplicate submission of the same logical order, not as a brand-new order.

What idempotency does not mean:

  • It does not mean every request is rejected after the first one
  • It does not mean the client cannot retry
  • It does not mean the server must return an error for duplicates

What it does mean:

  • The client may safely retry
  • The API may safely receive the same logical order more than once
  • The worker should not produce duplicate completed side effects for that same logical order

For this assignment, you may assume that once a worker successfully claims a logical order for processing, that worker does not crash before either completing the work or recording the completed result. You do not need to design crash recovery for a worker that fails after claiming the order.

Recommended pattern:

  • Build a stable key from clientOrderId
  • Use Redis to claim that logical operation once
  • Skip duplicate processing when the claim already exists

If you use SET ... NX in Redis, explain where it runs and why that placement protects correctness.

You may enforce this at the API boundary, in the worker, or in both places. The important thing is that your explanation matches your implementation.

A useful way to think about the flow is:

  1. The client creates clientOrderId
  2. The API receives the request and checks whether that logical order is already known
  3. If it is new, the API stores state and queues work
  4. If it is a duplicate, the API returns the existing state instead of creating new work
  5. If duplicate work somehow reaches the worker, the worker should still avoid completing the same logical order twice

Why not let the API create the idempotency identifier?

Because then every retry would arrive without a stable pre-existing identity. The server would see repeated requests, but it would have no reliable client-provided way to know that they represent the same logical order.

Why not build the identifier from customer name plus date and time alone?

Because retries might happen at a different time, and different legitimate orders can share similar customer data. A client-generated stable identifier is simpler and more reliable.

For this homework, a very reasonable pattern is:

  • browser kiosk page creates clientOrderId = kiosk-ui-0001
  • browser retry reuses clientOrderId = kiosk-ui-0001
  • simulator kiosk kiosk-03 creates clientOrderId = kiosk-03-0042
  • simulator retry reuses clientOrderId = kiosk-03-0042

If your system can explain and demonstrate that pattern clearly, you are handling the core idempotency idea correctly.

Suggested Sprint Plan

Do the work in this order. This is the safest path through the assignment.

Step 1: Start With the Containers

Before you build the whole feature, make sure you can start:

  • the API container
  • the worker container
  • the kiosk-sim container
  • the Redis container

The first small win is getting docker compose up --build to work. Your services do not need to do anything to have them up and running - from there you can incrementally add features.

Step 2: Build the API Before the UI

Get POST /orders and GET /orders/:clientOrderId working first.

At this stage, it is okay if you test with curl or Postman before you build the HTML pages.

Your first goal is:

  • Accept an order
  • Store it
  • Return a fast response

Step 3: Add the Queue

Once the API can accept an order, change it so it does not do the slow work directly.

Instead:

  • Store the order state
  • Put the job into Redis
  • Return quickly

This is where the system starts to feel like a real scalable distributed application.

Step 4: Build the Worker

Now make the worker:

  • Wait for jobs
  • Take a job from Redis
  • Simulate the work with a short delay
  • Update order state

Once this works, your monitoring dashboard will have something meaningful to show.

Step 5: Add the Kiosk Page

Build a simple page with a form.

A good kiosk page should let the user:

  • Enter order details
  • Submit through a normal HTML form
  • See a response right away

Keep it simple. A form and a response area are enough.

Step 6: Add the Kiosk Simulator Service

Build the separate kiosk-sim service after the core API and worker flow is working.

At this stage, your goal is to create a process that:

  • Starts N simulated kiosks
  • Sends orders concurrently to the API
  • Gives each kiosk a distinct kiosk identifier
  • Generates clientOrderId values that include the kiosk identity
  • Sometimes reuses a previously sent clientOrderId to simulate retries safely
  • Uses configurable environment variables from compose.yml
  • Produces logs that help you observe parallel submissions

Keep this service small. It is a simulator, not a full application.

Step 7: Add the Monitoring Dashboard

Build a second page that helps someone watch the system.

A good monitoring dashboard might show:

  • Recent orders
  • Current status of each order
  • Whether an order was a duplicate
  • Timestamps or attempt counts

You can use a normal browser refresh, a dedicated refresh button, or a short timed refresh to make state changes visible. This should not be fancy - otherwise you risk spending too much time on things that are not important for the assignment.

Step 8: Add Idempotency Last

Once the normal flow works, test duplicate submissions.

Try sending the same logical order twice. Then make sure:

  • The system does not do duplicate completed work
  • The duplicate is visible in logs or state
  • Your write-up explains why the design is safe

This last step turns the project from "works on the happy path" into "works like a real system."

Design Tips

If you are not sure how to organize the data, keep it simple.

One reasonable approach is:

  • One Redis list for queued jobs
  • One Redis key or hash per order
  • One stable clientOrderId per logical order
  • One simple kiosk loop per simulated kiosk in the kiosk-sim service

You do not need a database. Redis is enough for this assignment.

You also do not need fancy frontend code. Plain HTML plus server-rendered pages is enough.

Common Mistakes To Avoid

  • Doing the slow work inside the request handler instead of in the worker.
  • Building the UI first before the API contract works.
  • Forgetting to store enough state to power the monitoring dashboard.
  • Treating duplicate requests as an error instead of handling them safely.
  • Generating the idempotency identifier on the server instead of having the client send a stable one.
  • Using kiosk IDs that can collide across simulated kiosks.
  • Hard-coding the kiosk simulator behavior instead of making it configurable through Compose environment variables.
  • Making the system too large or too complicated.
  • Submitting code without testing the full flow from browser to worker.

Suggested Validation Flow

You may use any commands you want, but your evidence should cover at least this flow:

docker compose up --build -d
docker compose logs -f worker
docker compose logs -f kiosk-sim
open the kiosk page in a browser
submit one order through the kiosk page
let the kiosk-sim service submit several orders in parallel
submit the same logical order again through the kiosk page using the same clientOrderId
open the monitoring dashboard and observe status changes
curl http://localhost:3000/orders/kiosk-01-0001
docker compose down

Your exact ports, field names, and output format may vary, but the evidence must make these behaviors clear:

  • First submission is accepted and queued
  • Parallel kiosk submissions can be observed
  • Duplicate submission is recognized
  • The kiosk page works through normal browser form submission
  • A previously used client-generated ID can be resubmitted to demonstrate safe retries
  • The monitoring dashboard clearly shows updated state after refresh or revisit
  • Worker processes the order once
  • Final order state is visible

Evidence Deliverables

Your evidence bundle should help us understand the system in a few minutes.

Include clear proof of these moments:

  1. The stack starts successfully
  2. The kiosk page is visible
  3. A new order is accepted
  4. The kiosk simulator generates parallel order activity
  5. The monitoring dashboard shows status changes
  6. A duplicate order is handled safely
  7. The worker logs show background processing

Good evidence is more valuable than a long explanation.

Submission Deliverables

Submit one folder named hw01/ with this exact structure:

hw01/
brief.md
shots/
vids/
code/

What Goes in Each Part

brief.md Implementation Brief

This is the main implementation brief that we will read.

It should include:

  • Your name, umass email, spire id
  • How to run the project
  • How to test the project
  • A short architecture explanation
  • A short explanation of the kiosk-sim service and its environment variables
  • A short explanation of your idempotency strategy, including how clientOrderId is created and reused
  • An AI Use Statement
  • Links to the screenshots you want us to review
  • Links to the videos you want us to review

Important rule:

We will only review screenshots and videos that are linked from brief.md. We will only review enough to feel like it provides enough evidence. The videos, if any are provided, should be very short and self-explanatory.

If a file exists in shots/ or vids/ but is not linked from brief.md, you should assume it will not be reviewed.

shots/

Put screenshots here.

Use screenshots to show clear moments such as:

  • The kiosk page
  • The kiosk-sim logs or console output
  • The monitoring dashboard
  • A successful order submission
  • Parallel kiosk activity
  • A duplicate submission being handled safely
  • Worker logs or status output

vids/

Put short video clips here.

Good videos are very short and focused. A few small clips are better than one long confusing video.

Useful video ideas:

  • Placing an order from the kiosk page
  • Watching the kiosk-sim service generate concurrent requests
  • Watching the monitoring dashboard update
  • Showing duplicate protection working

code/

Put your implementation here.

This folder should contain the actual project code, including:

  • A dedicated folder for the API service called api
  • A dedicated folder for the worker service called worker
  • A dedicated folder for the kiosk simulator service called kiosk-sim
  • The HTML views
  • Dockerfiles
  • docker-compose.yml or compose.yml
  • Any small helper files needed to run the project

The grader should be able to enter code/ and run your project from there. Here is the recommended code folder structure:

.
├── api
│ ├── Dockerfile
│ └── server.js
├── compose.yml
├── kiosk-sim
│ ├── Dockerfile
│ └── simulator.js
├── redis
│ └── Dockerfile
└── worker
├── Dockerfile
└── server.js

The redis/ directory shown above is optional. Include it only if you are customizing the Redis container. If you use the standard Redis image directly from Docker Hub with no changes, compose.yml may reference that image and no code/redis/ folder is needed.

Scope Guidance

Do not overbuild this.

A strong submission is a small, clean system with:

  • One API service
  • One worker service
  • One kiosk simulator service
  • One Redis service
  • One queue
  • One simple kiosk page
  • One simple kiosk-sim process that generates parallel traffic
  • One simple monitoring dashboard
  • One clear idempotency rule
  • Clear reproducible evidence

You are practicing system structure and correctness, not building a feature-rich application.

If you are deciding between:

  • A smaller system that works clearly
  • A bigger system with extra features that are half-finished

pick the smaller system.

Required Deliverables

Submit a .zip file to Canvas by the assigned due date.

The zip file should contain exactly one folder named hw01/.

  1. One folder named hw01/
    • with brief.md, shots/, vids/, and code/
  2. A completed brief.md
    • explain the architecture, HTML request flow, Redis usage, kiosk-sim design, idempotency strategy, and AI use
  3. Screenshots in shots/
    • only screenshots linked from brief.md will be reviewed
  4. Videos in vids/
    • only videos linked from brief.md will be reviewed
  5. Implementation in code/
    • include the full runnable project

AI Use Expectation

AI use is expected and encouraged for this assignment.

This is not because the assignment should be outsourced. It is because the assignment asks you to connect several tools and layers quickly: Docker, Compose, Express, Redis, HTML, asynchronous workers, a small simulator service, and idempotency. Using AI for scaffolding, debugging, explaining errors, drafting handlers, or sketching templates is reasonable here.

You are still responsible for:

  • understanding the code you submit
  • verifying that the system actually works
  • checking that duplicate requests do not create duplicate completed work
  • accurately documenting how you used AI

Good ways to use AI on this assignment:

  • ask for a starter Dockerfile
  • ask for help wiring an HTML form submission flow
  • ask for help debugging Redis connection errors
  • ask for a simple worker loop
  • ask for a simple kiosk simulator loop that runs N clients in parallel
  • ask how to explain idempotency in plain language

Bad use of AI:

  • pasting in code you do not understand
  • trusting generated code without testing it
  • claiming behavior works when you did not actually verify it

Grading

Teaching staff should primarily grade the submission by reading brief.md.

The goal is fast, high-signal grading based on the document and its linked evidence, not on manually running code.

code/, shots/, and vids/ are still part of the submission, but we will mostly review only what is surfaced clearly through brief.md. Manual code execution is not expected during normal grading. If simple automated checks are available, staff may use them for basic validation, but the grading workflow should remain document-first.

Teaching Staff Guidance

Knock-Out Checklist

Check these first:

  • hw01/ folder is present
  • brief.md is present
  • brief.md includes student name, UMass email, and SPIRE ID
  • brief.md links the screenshots and videos to review
  • code/, shots/, and vids/ are present
  • brief.md includes an AI Use Statement

If basic submission materials are missing, note that before doing detailed grading.

Quick Grading Rubric

CriterionExceedsMeetsNeeds ImprovementBelow ExpectationsNo Submission
Submission completenessbrief.md is complete, well organized, and makes the submission easy to review quickly.brief.md is present and covers the expected sections well enough to review.brief.md is present but uneven, thin, or missing some important parts.brief.md is confusing, incomplete, or difficult to use.No meaningful brief.md submission.
Architecture and implementation explanationThe document explains the system clearly, with strong structure and useful technical choices.The document explains the main system structure and implementation choices clearly enough.The explanation is partly clear but leaves important gaps.The explanation is weak, vague, or hard to follow.No meaningful explanation of the system.
Evidence of working behaviorLinked screenshots and videos make the main behaviors easy to see and easy to trust.Linked evidence supports the main claims and is sufficient for quick review.Some evidence exists, but it is incomplete, weak, or hard to interpret.Evidence is sparse, confusing, or does not support the claims well.No meaningful linked evidence to review.
Correctness reasoningThe document gives a clear, convincing explanation of async flow, system state, and idempotency.The document explains the core correctness ideas well enough to support the submission.Correctness reasoning is partly present but weak, shallow, or incomplete.Correctness reasoning is unclear, incorrect, or mostly missing.No meaningful reasoning about correctness.
Professional communicationThe document is concise, readable, and includes the required metadata, AI disclosure, and useful evidence links.The document is readable and includes the required metadata and disclosure items.Communication is uneven or some required metadata or disclosure details are weak.Communication is hard to follow or missing important required information.No meaningful communication artifact.

Fast Grading Guidance

  • Start with the knock-out checklist.
  • Read brief.md first.
  • Only review screenshots and videos linked from brief.md.
  • Use best-fit judgment for each row.
  • Prioritize whether the document makes the claimed work easy to understand and easy to verify.

Choose the category that matches what you see in the submission quickly. Do not worry about mistakes. If a student sees a mistake or has a valid argument for a different grade assignment for a particular criteria, they will contact you.