Beginners often start with code and discover halfway that the pieces do not fit. Professionals spend a short time planning first, because changing a plan costs minutes and changing finished code costs days. The plan for a small app fits on one page. This lesson makes that page for the project you will build, and shows the thinking so you can repeat it for your own ideas.
Step 1: say what it does, in plain words
Write the purpose as two sentences a friend would understand. For us: *A signed-in person keeps a list of the jobs they applied for, moves each one through a status, adds notes and the resume they sent, and sees a few numbers about their search. Nobody can see anyone else's jobs.* Notice the last sentence. It is a rule, and rules like it drive the design: it is why every job must belong to a user, and why every query must filter by that user.
Step 2: list the screens
- Sign in and Create account.
- My jobs: numbers at the top, search and filters, a list with pages, and an “Add a job” form.
- One job: edit the details, attach or replace the resume, delete.
- A “not found” page.
Step 3: turn screens into API routes
For every thing a screen needs, write one route. A table is the clearest way. Look at the table in the plan file below: register, login, “who am I”, then the five job routes (list, add, read, change, delete), then statistics. Two details deserve attention. The list route takes query parameters for search, filter, sort and page, because the screen has those controls. And the statistics route is separate, because counting per status is a different question from listing jobs.
# Job Tracker: the plan
## What it does
A signed-in person keeps a list of the jobs they applied for, moves each one through a status
(saved, applied, interview, offer, rejected), adds notes, and sees a few numbers about their search.
## Folders
```
mern-job-tracker/
package.json shortcuts that run both apps
docs/PLAN.md this file
server/ Node.js + Express + Mongoose (the API)
client/ React + Vite (the screens)
```
## API (JSON, all under /api)
| Method | Path | What it does | Signed in? |
|--------|-------------------|--------------------------------------|------------|
| GET | /api/health | is the server up | no |
| POST | /api/auth/register| create an account | no |
| POST | /api/auth/login | get a token | no |
| GET | /api/auth/me | who am I | yes |
| GET | /api/jobs | list my jobs (search, filter, page) | yes |
| POST | /api/jobs | add a job | yes |
| GET | /api/jobs/:id | one job | yes |
| PUT | /api/jobs/:id | change a job | yes |
| DELETE | /api/jobs/:id | remove a job | yes |
| GET | /api/jobs/stats | counts per status | yes |
## Data
- **User**: name, email (unique), passwordHash, createdAt
- **Job**: user (who owns it), company, role, location, status, salary note, notes, appliedOn, resumeFile
## Rules we keep
- A person can only ever see and change their own jobs.
- Passwords are never stored as text and never sent back.
- Secrets live in `.env`, never in Git.
Step 4: design the data
Next, list what you must remember about each thing. A User has a name, an email that must be unique, and a password (stored only as a hash, never as text). A Job has an owner, a company, a role, a place, a status from a fixed list, a free-text pay note, notes, and later an attached resume. Think about what to store as text and what as a fixed choice: the status has five allowed values, so we will make the database enforce them. Pay is free text on purpose, because people write it as “£28k”, “₦150,000 per month” or “₹600 a day”, and forcing a number and currency would lose information.
Step 5: choose the folders
Two apps in one repository keep everything together while keeping their tools apart. server/ is the API with its own package.json. client/ is the React app with its own. A small package.json at the top has shortcuts. The files below create that top-level shortcut file, so one command can install both apps and one command can start both.
{
"name": "mern-job-tracker",
"private": true,
"version": "1.0.0",
"description": "Job Tracker: a MongoDB, Express, React and Node.js app",
"scripts": {
"setup": "npm install --prefix server && npm install --prefix client",
"server": "npm run dev --prefix server",
"client": "npm run dev --prefix client",
"dev": "concurrently -n api,web -c blue,green \"npm:server\" \"npm:client\"",
"build": "npm run build --prefix client",
"start": "npm start --prefix server"
},
"devDependencies": {
"concurrently": "^9.1.0"
}
}
npm run setup installs both apps. npm run dev uses the concurrently package to run the server and the client together in one terminal. You will use it from lesson 25, when the client appears.
Why plan the “boring” rules first?
Features are exciting, but rules are where real apps succeed or fail: who can see what, what happens with bad input, what is never stored. Writing three rules at the start (your own jobs only, no plain-text passwords, secrets in .env) means that you check every later lesson against them. Security added at the end is weaker than security designed at the start.
Your task
- Open
docs/PLAN.mdfrom the zip. Add one feature you would like (for example “interview date”) and write the route and the data field it needs. - Draw the data model on paper: two boxes (User and Job) and an arrow from Job to User.
- Write three rules for your own app idea, in the same style as the plan.
How to check it worked
- Every screen has the routes it needs in the table.
- Every field has a reason, and every rule can be checked later.
Summary
- Plan in this order: purpose, screens, routes, data, folders.
- Write rules (ownership, secrets, passwords) before features.
- Keep API and client as two apps in one repository.