# Weekly sales review board

> Draw weekly sales as charts and a table, updating the same board every week.

Source: https://mockflow.com/developers/examples/api/sales-review

A sales team reviews the numbers every Friday. Instead of a new spreadsheet each week, this example keeps one MockFlow board up to date: a revenue trend, revenue and deals by region for the latest week, and the numbers as a table. The first run builds the board; every later run replaces the data inside the same charts, so notes and stickies people added around them stay where they are.

[**Download the code**](/developers/assets/examples/mockflow-sales-review.zip) (Node.js 18 or later, no packages)

## What it creates

- A line [chart](/developers/reference/item-types/chart) of revenue by week.
- A bar chart of revenue by region and a pie chart of deals by region for the latest week.
- A [table](/developers/reference/item-types/table) with every week and region.

## How it works

1. Read `sales.csv` (`week,region,revenue,deals`) and work out what each item should show.
2. [Validate every payload](/developers/reference/items/validate-item-data) with `POST /item-types/{type}:validate` before touching the board. A `422` names the field that is wrong.
3. On the first run, [create the board](/developers/reference/boards/create-board) and [each item](/developers/reference/items/create-item), and save their ids in `state.json`.
4. On later runs, [replace each item's data](/developers/reference/items/update-item) with `PATCH /boards/{boardId}/items/{itemId}`. Position and size stay as people left them. An item someone deleted answers `404` and is drawn again.

## Run the example

Create an API key in the [developer console](/developers/console/) with the scopes `user:read` and `boards:write`, then:

```bash
cp .env.example .env        # paste your key into .env
node sales-review.js
```

Add a week of rows to `sales.csv` and run it again: the same board updates.

## The key code

```javascript
for (const [name, item] of Object.entries(items)) {
  const id = state.items[name];
  if (id) {
    try {
      await mf.patch(`/boards/${state.boardId}/items/${id}`, { data: item.data });
      continue;
    } catch (e) {
      if (!(e instanceof MockFlowError && e.status === 404)) throw e;
    }
  }
  state.items[name] = await mf.createItem(state.boardId, item);
}
```

## Adapt it

- **Marketing:** campaign spend, clicks and sign ups by channel, from your ads platform's export.
- **Support:** tickets opened and solved per week, and satisfaction by queue.
- **Product:** weekly active users and feature adoption beside the roadmap board.

## What you need

An API key with `user:read` and `boards:write`. Every plan.
