Skip to content

Chapter 2 — Walkthrough: Recently Viewed Products

Follow the full OpenSpec loop — propose → review → apply → archive — on a real feature. Every prompt is verbatim; every expected output is shown so you can verify your agent is on track.

  • Reading time: 15 minutes
  • Practical time: 45–60 minutes

Feature brief

What we're building: A "Recently Viewed" strip on the product catalog page (products/overview) that shows the last 10 products the user clicked, persisted in localStorage. Clicking an item in the strip navigates back to that product's detail page.

Why this feature: It is entirely frontend — no new API endpoints, no Spring changes, no database migrations. The OpenSpec loop is front-and-centre; the Angular/localStorage mechanics are secondary. A perfect first spec to write and review.

Scope:

  • New RecentlyViewedComponent rendered below the product grid in ProductCatalogPageComponent.
  • On every product-detail page visit, write the product id + name + image URL to a recently-viewed key in localStorage (cap at 10 items; newest first).
  • Strip is hidden when the list is empty.
  • No login required; localStorage is per-browser.

Step 1 — Propose

Open a new AI agent session (Copilot CLI or Claude Code) inside ~/lab-workspace/fullstack-onlineshop and run:

/opsx:propose add a recently viewed products strip to the product catalog page

The agent reads the OpenSpec instructions injected by openspec init and generates the proposal folder. This takes 30–90 seconds depending on the model.

Expected:
openspec/
└── changes/
    └── add-recently-viewed-products-strip-to-the-product-catalog-page/
        ├── proposal.md
        ├── specs/
        │   └── recently-viewed.md
        ├── design.md
        └── tasks.md

Note — folder name may vary: OpenSpec slugifies your prompt, and the agent may drop articles or shorten words. Use ls openspec/changes/ to confirm the actual folder name rather than assuming it matches the example above exactly.

Troubleshooting — CLI not found: If the agent responds "I don't recognise /opsx:propose", OpenSpec is not wired up. Run openspec update in the terminal and start a fresh agent session.


Step 2 — Read the proposal

Read each generated file before approving anything:

  1. proposal.md — Does the "why" match your intent? Does the scope paragraph match the feature brief above?
  2. specs/recently-viewed.md (or similar) — Are the acceptance scenarios concrete? Do they cover: adding on detail-page visit, capping at 10, empty-state hiding, and navigation on click?
  3. design.md — Does it name the right component (ProductCatalogPageComponent) and the right storage mechanism (localStorage)? Does it avoid introducing a backend call?
  4. tasks.md — Is the checklist ordered? Could a developer follow it without reading any other file?

Take notes as you read. You will use them in Step 3.

Troubleshooting — proposal too vague: If proposal.md is one paragraph and tasks.md has two items, the agent did not fully engage with the OpenSpec format. Prompt: "The proposal is too brief. Please re-read the OpenSpec instructions and expand proposal.md, specs/, design.md, and tasks.md with full detail."


Step 3 — Refine via dialogue

Based on your Step 2 notes, give the agent revision instructions in plain English. You do not need to edit the files yourself — the agent updates them.

Here is a worked example of two common refinements:

Increase the cap from 5 to 10:

The proposal caps recently viewed at 5 items. Change it to 10 in proposal.md,
specs/recently-viewed.md, and tasks.md — wherever the cap is mentioned.
Expected:
- proposal.md updated: "...stores the last 10 products..."
- specs/recently-viewed.md updated: acceptance scenario now reads "...no more than 10 entries..."
- tasks.md updated: implementation note references 10

Add a remove ("×") button per item:

Add an "×" button to each item in the strip so the user can remove it from
the recently-viewed list without refreshing the page. Update specs/recently-viewed.md
with a new acceptance scenario and add a task to tasks.md.
Expected:
- specs/recently-viewed.md gains a new scenario: "Given the strip is visible,
  when I click × on an item, that item is removed from the strip and from localStorage."
- tasks.md gains a task: "Add click handler on × button that splices the item
  from the stored array and triggers re-render."

After each round of revisions, re-read the updated files. Repeat this dialogue until you are satisfied with the spec. Do not move to Step 4 until you would be comfortable handing tasks.md to a colleague as the complete implementation brief.

Troubleshooting — agent skips a step: If the agent jumps straight to writing TypeScript after /opsx:propose, it may have bypassed the spec stage. Prompt: "Stop — do not write any TypeScript yet. We are still in the proposal stage. Please only update the Markdown files in openspec/changes/."


Step 4 — Apply

When the spec is approved, apply it:

/opsx:apply

The agent reads tasks.md and implements each item in order, writing TypeScript/HTML/CSS as needed. The agent narrates its progress in its own style — you will see it describe each task as it works through them (e.g. "Now implementing task 1 — creating the service…"). There is no fixed output format to match against. What matters is that the agent works through all items in tasks.md and finishes without errors.

After apply finishes, start the dev server (if it is not already running) and confirm the build is clean. The fullstack-onlineshop workspace contains two top-level directories: onlineshopui/ (Angular frontend) and onlineshopapi/ (Spring Boot backend). Navigate into the frontend directory:

bash
cd onlineshopui
npm install          # in case any new package was added (unlikely for this feature)
ng serve             # starts the dev server on http://localhost:4200 and reports any TypeScript errors

Leave ng serve running in this terminal — you need it for Step 5.


Step 5 — Verify

With the Angular dev server running, open http://localhost:4200:

  1. Browse to any product detail page. Note the product name.
  2. Navigate back to products/overview.
  3. Confirm the "Recently Viewed" strip appears below the product grid, showing the product you just visited.
  4. Visit two more product detail pages, then return to the catalog. All three should appear, newest first.
  5. Click an item in the strip — it should navigate to that product's detail page.
  6. (If you added the "×" button in Step 3) Click "×" on an item — it should disappear from the strip without a page reload.
  7. To verify the 10-item cap: visit at least 12 distinct product detail pages in total, then return to products/overview. Confirm the strip shows exactly 10 items, not 12. The oldest two should have been dropped.
  8. Open DevTools → Application → Local Storage → http://localhost:4200. Confirm the recently-viewed key holds an array of exactly 10 entries.

Tip (expanded profile): If you activated the expanded profile in Chapter 1, you can run /opsx:verify in a new agent session as a structured alternative to the manual checklist above. The command reads the spec's acceptance criteria and drives verification automatically.

If any of these checks fail, describe the failure to the agent:

The recently-viewed strip does not appear after visiting a product detail page.
The localStorage key is being written (I can see it in DevTools), but the
component does not update. Please check the change-detection strategy and
fix it without altering the proposal files.

Step 6 — Archive

Once all verification checks pass, archive the change:

/opsx:archive
Expected:
openspec/changes/add-recently-viewed-products-strip-to-the-product-catalog-page/
moved to:
openspec/changes/archive/YYYYMMDD-add-recently-viewed-products-strip-to-the-product-catalog-page/

Note: YYYYMMDD is replaced by today's date in YYYYMMDD format (e.g. 20260518-add-recently-viewed-...).

The archive folder is permanent record — future you (or a teammate) can read it to understand why this component exists, what alternatives were considered, and what the acceptance criteria were.


Recap

You just completed one full OpenSpec loop:

StepWhat happened
ProposeAgent generated proposal.md, specs/, design.md, tasks.md from a one-line idea
ReviewYou read the spec and caught vague wording before any code was written
RefineYou updated the cap and added a "×" button via dialogue — spec stayed the source of truth (part of the Review stage: loop back until the spec is approved)
ApplyAgent implemented exactly what tasks.md described
VerifyYou confirmed the feature works in the browser (part of the Apply stage: check against acceptance criteria)
ArchiveCompleted change is preserved for audit

Reference asset: If you want to compare your generated spec against a known-good example, see the reference folder (note: the reference uses a shortened folder name add-recently-viewed/ for readability — your workspace folder will be named add-recently-viewed-products-strip-to-the-product-catalog-page/):

These files represent what a thorough OpenSpec proposal looks like after one round of refinement. Your agent's output will differ in wording; what matters is that the structure and level of detail are comparable.


Next

Head to Chapter 3 — Apply on Your Own: Product Wishlist to run the loop independently on a more complex fullstack feature.

Copyright © MSG Systems Romania AI Labs