AI Global Academy Join the waitlist

Courses / The CRM

Lesson 5.4 · 60 minPipeline board

Duration~60 min in the lesson + ~30 min homework
PrerequisitesCheckpoint lesson-5.3; the browser connection from 1.6.
Checkpointlesson-5.4

What you will have

The student has a board at /admin/pipeline with one column per stage. A lead's status can be changed by dragging its card, from the keyboard, or from the lead card, and every change is written to lead_status_history with its time. Marking a lead lost asks for a reason.

Video

The video for this lesson is not recorded yet.

Prompts used in this lesson

Part 5 — Building the board

Prompt to Claude
Build the pipeline board at /admin/pipeline, replacing the placeholder, and
add status changing to the lead card.

Purpose: the owner sees the whole pipeline at once and moves leads between
stages; every move is recorded so the dashboard can later measure response
time and win rate.

Context: docs/crm-spec.md, the lead_status_history table, the lead card and
list from earlier lessons.

One door for status changes: a single server-side function that every
status change uses. It checks the new status is one of the five stages,
updates leads.status and inserts a lead_status_history row (from status, to
status, time, optional reason) as one transaction, so both are saved or
neither. If the new status equals the current one, it does nothing and
records nothing. A change to lost requires a non-empty reason.

Board:
- five columns in pipeline order: new, contacted, qualified, won, lost, each
  with its name and the number of cards;
- a card shows the lead's name, how long ago it was created and the first
  words of the message, and links to the lead card;
- cards within a column are ordered newest first;
- dragging a card to another column changes its status. The card moves at
  once; if saving fails, it returns to where it was and an error is shown;
- every card also has a "Move to" control usable with the keyboard alone
  and by screen readers, offering the other four stages;
- dropping or moving to lost opens a dialog asking for the reason; Cancel
  leaves the lead where it was;
- won and lost columns show only leads whose status changed in the last 30
  days, with a link to the full list filtered by that status, so the board
  stays readable.

Lead card:
- the status badge becomes a control that changes status through the same
  function, with the same lost-reason dialog;
- a new "History" section lists every status change for this lead, newest
  first: from, to, date and time in the business time zone, and the reason
  when there is one.

Drag and drop library: choose one yourself, but first check the package
registry and the library's own documentation, not memory. It must be
currently maintained and not deprecated, work with the React and Next.js
versions in this project, and support keyboard operation. Tell me which you
chose, its latest version and release date, and why, before installing it.

Constraints: all changes happen on the server for the signed-in owner only.
The board must be usable on a phone: columns scroll sideways, and "Move to"
works by touch.

Before you report, verify in a real browser using the browser connection;
when the login page appears, wait while I sign in myself. Check and report
on each: drag one lead from new to contacted, then confirm its badge in
/admin/leads, its History section on the lead card, and a new row in
lead_status_history; move a second lead using only the keyboard; move a
lead to lost, cancel the dialog and confirm nothing changed and no history
row was written; move it to lost with a reason and confirm the reason is
stored; drop a card back on its own column and confirm no history row;
change a status from the lead card and confirm the board shows it; check
the board at phone width. Run the build. Say plainly what you could not
verify.

Do along

  1. Pause at the prompt in Part 5. Run the prompt. Before approving the library, ask Claude to show the evidence that it is maintained; note the name in docs/crm-spec.md.
  2. Adapt the lost reasons: ask Claude to offer your four or five most likely reasons as quick choices plus a free-text "other".
  3. After Part 6, take one sample lead through every stage from new to won, using a different method for each move: drag, keyboard, lead card.
  4. Mark one lead lost, cancelling once and confirming once.
  5. After each move, look at the list, the lead card and the lead_status_history table.
  6. Do the "Check your work" steps, then run the commit and tag commands that end the lesson.

Check your work

  1. Open /admin/pipeline. Expected: five columns in order, each with a count; the counts of new, contacted and qualified match the list filtered by that status.
  2. Drag a lead from New to Contacted. Expected: the card stays in Contacted after a page reload.
  3. Open /admin/leads and find that lead. Expected: badge "contacted".
  4. Open the lead's card. Expected: a History line "new → contacted" with the current time.
  5. Open lead_status_history in the Supabase table view. Expected: a new row for that change.
  6. Without touching the mouse, move another lead with "Move to". Expected: it moves and a history line appears.
  7. Move a lead to Lost and press Cancel. Expected: the lead is where it was; no new history row.
  8. Move it to Lost with a reason. Expected: the reason is shown in History.
  9. Change a status from a lead card. Expected: the board shows the card in the new column.

Common problems

  • The card jumps back after dropping. → Saving failed and the board undid the move, as designed. → Read the error shown, then: "Dropping a card fails with this message: <message>. Find the cause and verify the fix in the browser."
  • The card moves but the list still shows the old status. → The screen changed but nothing was saved, or the list shows stored-earlier data. → "After a move, the list shows the old status even after reload. Check that the status function really runs and that the list is not serving a stale copy."
  • Status changes but there is no history row. → Some path bypasses the one door. → "Find every place that changes leads.status and make each use the single status function. List the places you found."
  • Dragging does not work on a phone. → Touch settings of the library. → Tell Claude what happens; in the meantime "Move to" works.
  • Claude proposes react-beautiful-dnd. → Outdated knowledge. → "That package is marked deprecated on npm. Check the registry and choose a maintained alternative."

Homework

About 30 minutes, on your own, after the lesson. No later lesson depends on it.

  1. A pretend week, on your phone. Open the board on your phone. Pick eight sample leads, invent what happened to each this week, and move them accordingly; mark at least two as lost with a reason. Leave at least one lead in every column. Deliverable: eight leads with a believable story. Done when: the History section on each of the eight cards matches the story you invented, and every move worked on the phone.
  2. What each lost reason would change. For each lost reason in your list, write one line: "If this became my most common reason, I would change …". Deliverable: a section "Lost reasons" in docs/crm-habits.md (your own notes; create it if missing). Done when: every reason has an action, or is marked "nothing to change".
  3. Where will leads pile up? Look at the column counts and think about your real week. Write two or three sentences: which column would fill first in your business, and what you would do on the day it holds more than ten cards. Deliverable: the sentences, in the same file. Done when: they name one column and one action.

If a task changed files in the project, commit and push without a tag.

Save your work

git add -A
git commit -m "Lesson 5.4: pipeline board, status changes with history, lost reason"
git tag lesson-5.4
git push
git push --tags