Project — Frontend & ML Product Thinking

Project Build this yourself, to the spec and rubric below — the module's standard. You build it on your own dataset, alongside the lessons.

A minimal frontend that turns a raw model output into a prediction a non-ML human can act on for the Adult / Census Income dataset — the product layer that sits on top of your own /predict endpoint and shows a probability honestly, not a bare yes/no dressed up as certainty.

Dataset Adult / Census Income — different from the lessons’ loan-default dashboard, so finishing it proves you can ship the product layer yourself, not that you replayed the lesson
Start from Fork dutchengineer-org/phase2-starter — ships train.py and the frozen package; run python train.py to produce the model, so the model is never the blocker. The /predict service behind it is your own M6 work in this same fork
Aim for The reference package — read it to see what good looks like; do not fork it. No version bump: the UI is a separate app that calls the deployed model over the network; it is its own thing with its own version, and the ML library it talks to keeps the version it already had
Done when It passes every line of the rubric below, then you push to GitHub
Project Build this yourself, to the spec and rubric below — the module's standard. You build it on your own dataset, alongside the lessons.

A minimal frontend that turns a raw model output into a prediction a non-ML human can act on for the Adult / Census Income dataset — the product layer that sits on top of your own /predict endpoint and shows a probability honestly, not a bare yes/no dressed up as certainty.

Dataset Adult / Census Income — different from the lessons’ loan-default dashboard, so finishing it proves you can ship the product layer yourself, not that you replayed the lesson
Start from Fork dutchengineer-org/phase2-starter — ships train.py and the frozen package; run python train.py to produce the model, so the model is never the blocker. The /predict service behind it is your own M6 work in this same fork
Aim for The reference package — read it to see what good looks like; do not fork it. No version bump: the UI is a separate app that calls the deployed model over the network; it is its own thing with its own version, and the ML library it talks to keeps the version it already had
Done when It passes every line of the rubric below, then you push to GitHub

Start here

  1. Fork the starterdutchengineer-org/phase2-starter, clone it, and install it. Already forked the Phase 2 starter in an earlier ship module? Keep building in that fork
  2. Work the tasks below in order — each maps to a lesson you just finished
  3. Check yourself against the rubric, then push and submit

By the end, someone who has never seen your model should be able to open the page, enter a record, and understand both what the model predicts and how confident it is, without reading your code and without seeing anything that should have stayed on the server.

The tasks

Do these in order; each maps to a lesson you just finished.

1. Get a working dashboard up (from Lesson 1)

  • Build one page that collects a record’s fields, fetches your M6 /predict endpoint, and renders the returned prediction on the page.
  • The happy path works end to end: type a record, submit, see the model’s output appear, against your actual running service, not a hardcoded mock.

2. Make it degrade gracefully (from Lesson 2)

  • Check the response status before you trust the body: a 200 is not guaranteed, and a non-200 must not be parsed as if it were a prediction.
  • When the API is down, slow, or returns an error, the page says so in plain language instead of breaking, showing a stale result, or hanging on a spinner forever.

3. Present the prediction honestly (from Lesson 3)

  • Surface the model’s confidence, framed so it cannot be misread: not a bare yes/no that hides a 51% call, and not a raw decimal a non-ML reader will take for a calibrated real-world frequency. A likelihood band or rank framing (Lesson 3’s fix) satisfies both.
  • Make the threshold yours, on purpose: state where the cutoff sits and why (in the README or on the page itself) rather than letting 0.5 decide silently.
  • Keep secrets out of the client: no API keys, internal URLs, or credentials baked into the page source. Anything sensitive stays server-side.
Hints
  • Start by hitting /predict from the browser console with fetch before you build any UI; once you can see the JSON come back, the page is just rendering that JSON.
  • To test graceful degradation, stop your M6 service and reload the page: whatever the user sees in that moment is your error handling. If it is a blank screen or a thrown exception in the console, you have work to do.
  • View Source on your own page and read it as an attacker would: if you can find a key, a token, or an internal hostname, so can anyone who opens DevTools.

Rubric — your project is done when

This is the standard the module holds you to (each bar maps to the lesson that taught it):

  • A working dashboard calls your API — the page sends a record to your M6 /predict endpoint and renders the returned prediction end to end. (Lesson 1)
  • Degrades gracefully — the page checks response status and shows a clear, plain-language message when the API is down or errors, instead of breaking or showing stale results. (Lesson 2)
  • Surfaces probability without misrepresenting confidence — a non-ML human sees how confident the model is, not a bare label that hides a borderline call. (Lesson 3)
  • Threshold is owned, not implicit — the cutoff is stated and justified, not left at a silent 0.5. (Lesson 3)
  • No secrets in client code — no keys, tokens, or internal URLs in the page source. (Lesson 3)

Open your own page, stop the API, and read the source as if you had never seen it: for each rubric line, confirm it holds, and if one fails, name which lesson’s failure mode you reintroduced.

Submit

Use the branch workflow from the M1 git lesson, not commits straight to main. Branch off main (git checkout -b m7-frontend), build this module’s piece there, and open a pull request to merge it back once it meets the rubric. main stays the last-good version of the product you carry forward, so a half-finished module never breaks what later modules build on.

When your repo meets every rubric line, merge your branch to main, push it to GitHub, and submit the repository URL here. (Submission coming soon.)

Coming soon

This lesson is not published yet. Join the waitlist to hear when it ships.

Coming soon