Take-home exercise

SimpleCRM: Monthly Forecast

Build a forecast feature for a small CRM.

Time ~60 minutes Stack React + TypeScript + Express + SQLite

Heads up. This is a fake codebase with no history, but the tradeoffs in it are examples of real ones: stuff shipped before the requirements were nailed down, edges nobody got back to, choices that aged poorly. Tell us what you’d change about it (and what you’d leave alone) in your writeup.

The setting

SimpleCRM is the in-house sales tool for a small company that makes widgets. Sales reps use it to track potential customers (leads), the deals they’re working (opportunities), and where each deal sits in the pipeline. A typical widget sale runs several months: first contact, conversations, demo, negotiation, signed contract.

Day-to-day contact management is rough. Bonus points if you make it less painful. But the real ask is reports and projections. The team needs to see where their pipeline is concentrated and where revenue is likely to land. Focus there.

What you’re building

Four user stories. Each notes what’s already there and what to add.

  1. Close date on opportunities. As a sales rep, I want each opportunity to carry an expected close date, so the team can forecast against it.

    The opportunity data model doesn’t have a close date today. You’ll need to add the column, the API plumbing, and a way to set it in the UI. Existing opportunities won’t have one until someone fills it in; how you handle that is up to you.

  2. Add and edit opportunities in the UI, including their custom fields. As a sales rep, I want to add new deals and edit existing ones from the browser, including the custom fields we tag them with for reporting.

    There’s no opportunity create/edit UI today: under a lead you can see existing opportunities and delete them, but that’s it. The backend POST and PUT endpoints already accept everything you’d need to send. Custom-field definitions (under Settings › Manage Custom Fields) already include opportunity-scoped fields, and the seeded opportunities already have values in some of them. You just can’t see or edit those values in the UI yet.

  3. Monthly forecast. As a sales manager, I want a page that buckets open opportunities by the month they’re expected to close, so I can see what’s likely to land per month.

    New page. Six buckets for the next six calendar months, one for opportunities whose close date is already in the past, and one for opportunities more than six months out. Per bucket, show at least a count and a total expected value. Decide what to do with opportunities that have no close date, and with opportunities you don’t consider open.

  4. Group the forecast by a custom field. As a sales manager, I want to split each month-bucket by the value of an opportunity custom field (e.g. region), so I can see where my pipeline is concentrated.

    Add a control to the forecast page that lets me pick which opportunity-scoped custom field to group by, or no grouping. Opportunities that don’t have a value for the chosen field still need to land somewhere visible.


Setup

Clone the repo and run the dev server:

git clone https://github.com/SeniorPlace/simple-crm.git
cd simple-crm
npm install
npm run dev

That single command starts both processes:

Open the client URL in your browser. The database seeds itself on first boot with a handful of leads, stages, and opportunities, plus a couple of pre-defined custom fields.

Layout

code/
  client/   React + Vite frontend
  server/   Express + TypeORM API

What to send us

When you’re done, email both of these addresses:

Pick whichever submission style you prefer:

  1. Publish your code. Push to a public GitHub or GitLab repo and put the link in the email.
  2. Send an archive. If you’d rather keep things on the DL, attach a zip or tar of the repo to the email.

Include a short writeup in the email body. This is how we’ll understand your choices, so spend a few minutes on it. Tell us:


FAQ

Do you care about styling?

This is a full-stack role, and attention to detail on the frontend matters. The forecast page should look like something you’d put in front of a user. Pixel-perfect isn’t required, but “shoved everything in a list and called it done” isn’t enough.

Do I need to write tests?

Do what you’d do in your normal day-to-day work. We’re interested in your thought process about which tests you choose to write and which you skip. Mention it in your writeup.

What if I don’t finish?

Don’t worry about it. Submit what you have, plus a paragraph on what you’d do next. Most candidates don’t finish, that’s expected.

Can I change parts of the existing codebase?

If you’d change something at your job, change it here. We want to see how you actually work.

What if I find a bug?

Decide whether to fix it, work around it, or just note it. Tell us why in your writeup.

How do I submit?

Email hiring@seniorplace.com and jd@seniorplace.com with either a link to your public repo or an attached archive, plus your writeup in the email body.