- Node.js 18 or newer
- An Anthropic API key for recommendations
From the repository root, install all workspace dependencies:
npm installAn Anthropic API key is required. Set ANTHROPIC_API_KEY in backend/.env.example. The optional ANTHROPIC_MODEL value defaults to the configured Sonnet model.
Restart the backend after changing environment values.
From the repository root, start both the frontend and backend together with one command:
npm run devOpen the frontend at http://localhost:5173.
The backend runs at http://localhost:3001.
Press Ctrl+C to stop both processes.
I'm pretty simple and try to keep it that way. The tools I used:
- OpenCode
- GPT-5.6 Luna
The following are a few of my core prompts, each one done in steps so I can better review the output from the LLM, instead of a single large Prompt-n-Pray request. I prefer to remain in the loop every step of the way and push back or make manual edits as needed.
(Note: A major decision I made was to quickly build a monorepo so you only need to run one command to launch both backend and frontend. Also, all of this wasn't as complex as it looks 'on paper'. Initial scaffolding was done in about 20 mins. Testing and debugging took much longer.)
In the current project directory, we're going to create a monorepo that will have two directories in the root, which already exist:
- /backend
- /frontend
The project should be launched from the root with a single npm run dev command, which will start up both the backend (Node/Express) and the frontend (React/Vite) in the same terminal session.
npm install should also run installs for both backend and frontend from the root.
I want you to pipe each child process’s output through the root launcher, prefix every line with a colored process tag such as [_backend] and [frontend], and keep both streams visible.
There should be an env.example with the entries for using the Anthropic API Key (but the actual key should not be included; the value should remain blank).
Test and check for errors.
On the backend, it should run Node.js with Express, Nodemon, Cors, Dotenv, and the Anthropic-AI SDK library.
I want a common setup with the file structure, but simplistic.
- /backend/src/api/recommendations
- /backend/src/services/anthropic
The backend should return proper status/error codes.
The /recommendations endpoint will import the anthropic service and call it with the data posted to it from the frontend.
The anthropic service should use the SDK to send requests to Anthropic with a max tokens of 500. I want it to use the Sonnet model, with this instruction prompt (simplified version):
You are a product recommendation assistant.
Compare only the products provided.
Return valid JSON only with this structure:
{ "beginner": { "productId": "string", "reason": "string" }, "expert": { "productId": "string", "reason": "string" } }
The code should be simple and to the point, no over-engineering, and should handle erorr/edge cases.
Test and check for errors.
I have already provided the file system structure in /frontend for:
- /components
- /pages
- /services
On the frontend, set up a React/TypeScript project with Vite and Phosphor Icons.
Set up Vite/TS with aliases for:
- @components
- @pages
- @services
I want a default, quick display of "Hello World" from /pages/products.
Test code and check for TS errors.
With the full-stack running, the prompts after were many smaller ones, targeted at creating the flow:
- Load products → search products → select top three → send to Anthropic on User Click → display recommendations → handle loading/errors (simple).
I let the LLM code the backend and most of the frontend, but I did structure the file systems for those myself. I checked every diff in Git and pushed back when needed.
I wrote the CSS since LLMs (in my experience) tend to get a bit too creative with styling and always default to a flat list of classes. I like to nest classes for readability and scoping. Plus, I enjoy hand-writing CSS. It didn't take long!
The code that came out was mostly good, but the LLM did make some assumptions, such as creating a "health" endpoint to test the backend from a frontend that didn't exist yet.
It also assumed I wanted a "Sorting" function when I asked it to create a search function, initially. And it tried to create params for an endpoint that didn't accept a search param.
It created a massive dev.mjs for the monorepo that didn't need to be there, so I had it removed, moving any important bits to other files.
Overall, on a small project like this, the LLM did pretty well. But I also knew what to ask for since I've done this several times, so the LLM didn't have to make too many assumptions beyond what's listed above.