Lab · Project
One board, one question: did we deliver the agreed hours?
59 clients · 10 team members · one monthly close
Ten team members log hours for 59 clients in Productive. Whether a client actually received the agreed quota was still written down nowhere. Every month that meant: pull the data from Productive by hand, check it against the spreadsheet with client budgets, and work out how many hours we could deliver next month. Per client. By hand. Every month again.
I built the board to answer exactly one question: did we deliver the agreed hours for this client? Everything else is decoration.
The card: one big number, three rules
Every client is a card, and the card carries one big number – the target, meaning quota plus carryover, capped at zero. Behind it stand three rules that keep the system honest. The carryover always calculates from the quota, never from the target; otherwise a debt freezes in place forever. The tolerance only colors, it never calculates; a green month can still carry a carryover. And the actual comes live from Productive on every call, cached for ten minutes – counting only the projects assigned to the client. No heuristics over client names, no company matching. If an ads project is not on the list, it does not count.
Missing logged hours are a data error, not a status. They block the close. Lifting that block is a deliberate act: tick the box, type a reason of at least ten characters.
The monthly close
A month is closed after the meeting; from then on it is frozen. The numbers come from the snapshot, no longer from Productive. The walkthrough runs in a fixed order – hours not logged first, then over budget, then underutilized, finally on track. Clients without a project ID or without a quota do not appear. For over budget and underutilized, a reason is mandatory, because documenting the deviation is the point of the meeting.
The current month cannot be closed; it is not over yet. Closing twice does not work either: the second attempt bounces, the snapshot stays untouched. A closed month can be reopened, with a reason – the old snapshot is archived, never deleted. And if someone changes the hours in Productive afterwards, the snapshot wins: the board shows a notice, the numbers stay.
The protocol
A closed month can be taken along as a file: Markdown, one file, plain text – no PDF, no Excel. It is called Monthly-Check_2026-07.md. First the agency total, then one section per account manager, inside it the clients sorted by status, red ones first. Notes appear verbatim: whatever was typed in the meeting lands unchanged in the protocol, including the reason for an override. Clients without a project ID or without a quota sit at the end under “not covered” and flow into no total. The numbers come from the snapshot – an export from today and one from next year are identical, even if someone changes the hours afterwards.
Architecture
Frontend: React, Vite, and TypeScript, Tailwind for styling, Recharts for the trend line – built as static files, served by the same server. Behind it, Node and Express on Google Cloud Run. The data lives in two places: hours come live from the Productive API, while client configuration and snapshots of closed months sit as versioned JSON objects in Google Cloud Storage. Secrets in Secret Manager, access by password.
One detail for engineers: the calculation core is extracted into its own package, without a single network call; everything is computed in whole minutes, tested with 100% branch coverage. It is the one place where a bug devalues the entire board. That is why it is isolated from everything else.
What the board does not do
It writes nothing back to Productive; hours are logged there, not here. It does not bill: no invoicing, no forecasts. It deletes no clients, only archives them, because snapshots reference the ID. And it knows no roles and no login – access ends at the domain level.
It started with a spreadsheet next to Productive and a calculator. Today one card per client answers the one question, and the monthly close is a single meeting with a protocol. Which number do you still calculate by hand every month? Write to me.