Webbo3 Level 2 · JavaScript Development · Day 15 of 20
Project 3: Build a Product
A solo build that belongs in your portfolio, and a page of planning before a single line of code.
By the end of today you can
- Write a short PRD that turns a vague idea into a scoped build
- Choose your own product and defend the choice
- Ship something with state, storage, real UX and accessibility
- Explain the trade-offs you made and what you deliberately left out
Project 1 asked whether you could make a page work. This one asks whether you can build a product: decide what it is, decide what it is not, and finish it. The deciding is the hard part, and it is why today starts with writing rather than typing.
Choose one
| Product | The interesting problem in it |
|---|---|
| Personal finance tracker | Categories, monthly totals, a chart you draw yourself from divs |
| Job application tracker | Stages, dates, "no reply in 14 days" logic |
| Student management dashboard | Records, grades, filtering, an average that must always be right |
| Expense splitter | Who owes whom, which is genuinely fiddly arithmetic |
| Event manager | Dates, capacity, "sold out" and past-event states |
Or propose your own, provided it has records the user creates, at least one derived value that must stay correct, and something worth filtering.
1. Write the PRD first
A Product Requirements Document is not corporate paperwork. It is one page that stops you building the wrong thing for six hours. Write it before you open your editor, and keep it in the repository as PRD.md.
# Job Application Tracker
## Problem
I apply to a lot of roles and lose track of which I have heard back from,
which need chasing, and which are dead. Right now this lives in my head and
in a WhatsApp message to myself.
## Who it is for
Me, and anybody job hunting who does not want a spreadsheet.
## The one thing it must do well
Tell me, at a glance, which applications need action today.
## Core features (this build)
- Add an application: company, role, date applied, link, status
- Statuses: applied, interviewing, offer, rejected
- Mark an application as needing follow-up if applied over 14 days ago
and still "applied"
- Filter by status, search by company
- Everything persists across a refresh
## Out of scope (deliberately)
- Accounts and login. One person, one browser.
- Email reminders. There is no backend.
- File uploads for CVs.
## User stories
- As a job hunter, I can add an application in under 15 seconds
- As a job hunter, I can see which applications are stale without reading dates
- As a job hunter, I can find a company by typing three letters
## How I will know it is done
- I can add 10 applications, close the browser, reopen, and see all 10
- The stale badge appears on exactly the right rows, tested at 13, 14 and 15 days
- Lighthouse Accessibility above 95
- It is usable on my phoneThe out-of-scope section is the most valuable part
It is the one that stops you at 4pm adding login "quickly". Write down three things you are deliberately not building and why. In the assessment you will be asked about them, and "I decided that was out of scope because..." is a much better answer than a half-finished login screen.
2. What it must include
| # | Requirement | From |
|---|---|---|
| 1 | Create, edit and delete records | Days 3, 4 |
| 2 | One state object, and render from it | Day 11 |
| 3 | Persists in localStorage, and survives corrupt data | Day 11 |
| 4 | Search and at least one filter | Day 9 |
| 5 | At least one derived value that is always correct | Day 11 |
| 6 | Split into modules | Day 6 |
| 7 | Form validation with messages that say what to do | Day 13 |
| 8 | Full keyboard operation and a visible focus ring | Day 13 |
| 9 | Empty state, and a confirmation before destructive actions | Day 9 |
| 10 | Works at phone width | Month 1 |
The derived value is where the marks are
A total, an average, a count of what is overdue. It must be calculated at render time, never stored. The assessor will add a record, delete one, edit one and watch whether the number stays correct. This is the single most common place these projects fail.
3. How to spend the day
| Time | Doing | Not doing |
|---|---|---|
| First 45 min | The PRD. Sketch the screen on paper. | Opening your editor |
| Next 90 min | Data model and state. Get add and list working, ugly. | Any CSS at all |
| Middle | Edit, delete, filter, search, the derived value. | Polishing |
| Next | Storage, empty state, validation. | New features |
| Last 90 min | Accessibility audit, phone width, README, deploy. | Anything new |
| Final 20 min | Delete dead code. Rename anything vague. | Adding "one more" |
The trap that catches half a cohort
Styling at hour two. It is the comfortable, familiar work you did last month, and it feels like progress. Then at 4pm the delete button does not work and there is no time. Ugly and finished beats beautiful and broken, every time, and it is marked that way.
4. The rubric
| Criterion | Marks | What is looked at |
|---|---|---|
| PRD and scope | 15 | Is the problem real, is the scope sane, is there an honest out-of-scope list |
| It works | 25 | All ten requirements, tested by somebody who did not build it |
| State and correctness | 20 | One source of truth, derived values that stay right under editing and deleting |
| Code quality | 15 | Modules, naming, no repeated blocks, no dead code |
| UX and accessibility | 15 | Keyboard, focus, empty states, validation messages, phone width |
| Explanation | 10 | Can you justify your scope and your trade-offs |
The questions you will be asked
- Show me the derived value. Now delete a record while I watch.
- What did you leave out, and what would you build next?
- What happens if I open DevTools and put rubbish in your storage key?
- Which part of this took longest, and was it the part you expected?
- Show me a function you are not happy with, and tell me why.
That last question feels like a trap. Is it?
No, it is the opposite. Every codebase has a function its author is not happy with, and being able to point at it and say why is a strong signal: it means you have standards and you know where you fell short of them.
"There isn't one" is the weak answer. It says either you have not read your own code or you cannot yet tell good from bad.
Hand in
- GitHub repository, with
PRD.mdat the root and a commit history that shows the order you built things in. - README: what it is, a screenshot, how to run it, what is out of scope, what you would do next.
- A deployed link. GitHub Pages, Netlify or Vercel. Ten minutes, and from Day 18 it is compulsory anyway.
Questions you will have today
My idea is too ambitious. Do I change it or cut it down?
Cut it down, and write the cut into the out-of-scope section. Changing your idea at 11am costs you the whole morning. Shrinking it costs you one paragraph, and "I scoped this down when I realised the date logic was the hard part" is a genuinely good thing to be able to say in the assessment.
Should I use a library for charts, dates or storage?
Not this week. The point of this project is that you can do these things yourself, and you know from Day 12 that the browser does more than beginners assume. A bar chart is a row of divs with a width. A date is Intl. Storage is four methods. Reach for a library in Level 3 when you can say what it is saving you.
My derived value goes wrong after I delete something. Where do I look?
You stored it instead of calculating it. Search your code for anywhere the total or count is assigned rather than computed inside the render. That is almost certainly the line. Delete it and compute the value in render() from the current state instead.
How much CSS is enough?
Readable, spaced, works at phone width, visible focus ring. That is the bar and it is fifteen marks shared with UX. There are no marks for a colour palette. If your form validation messages are still "Invalid" at 4pm, that is where the next hour goes, not into shadows.
Tick before you move on
- ☐ My PRD was written before any code and is in the repository
- ☐ All ten requirements work, checked by somebody else
- ☐ The derived value stays correct after adding, editing and deleting
- ☐ Corrupt storage does not break the app
- ☐ Keyboard-only operation works and Lighthouse Accessibility is above 95
- ☐ I deleted dead code and renamed everything vague before submitting
Quick recap
Decide what it is not, in writing, before you decide what it is · Data and behaviour first; CSS last, and only when it works · The derived value must be calculated, never stored · Ugly and finished beats beautiful and broken
Next week: the professional week. AI you supervise, security, shipping, the job hunt, and a final team build for a real client.