Drawcheck

Method

A pay application review is a document that gets argued with. That is the whole specification.

When an owner reduces a draw, the contractor asks why, usually in writing and sometimes through counsel. Anything that cannot be reproduced on paper gets paid anyway. Three things follow from that.

Show both numbers, not a verdict

Every exception names the figure that was claimed and the figure the record supports, and the difference is the amount at issue. Not a flag, not a risk score. A number the contractor can either explain or accept.

Cumulative figures are the trap

The continuation sheet states work completed to date, not work completed this period. Retainage held is also cumulative. Summing either one across the draw history restates the same money once per month and produces an exposure figure several times too large. Differencing has to happen exactly once, in the view that owns the draw, and every rule downstream has to read that column rather than recompute it.

Approved is not the same as submitted

The adjusted scheduled value includes approved change orders only. Pending ones are excluded on purpose, because billing against a pending change order is how the price of a change quietly stops being negotiable. The rule that catches it needs both figures in the same row, which is why the change order total is carried on the line rather than looked up when a page renders.

-- Every figure on a G702 continuation sheet is cumulative. The money that
-- actually moves on a draw is the difference against the previous one, so the
-- difference is taken once, in one place, and never summed downstream.
select
  pa.id, pa.app_no,
  sum(lp.work_completed_to_date) + sum(lp.materials_stored)
    - sum(lp.retainage_withheld)
  - coalesce(lag(sum(lp.work_completed_to_date) + sum(lp.materials_stored)
                 - sum(lp.retainage_withheld))
             over (partition by pa.contract_id order by pa.app_no), 0)
      as current_payment_due
from pay_apps pa
join v_line_periods lp on lp.pay_app_id = pa.id
group by pa.id, pa.app_no, pa.contract_id;

Built on

Next.js App Router with server components querying Postgres directly, Supabase for the database, Tailwind, deployed on Vercel. All derived money lives in SQL views, so the totals on a screen and the totals in a certification letter are the same expression evaluated once.

About this demonstration

Four projects, seven contracts and their complete draw history, generated with a fixed seed so the same defects appear every time. Contract dates are stored relative to the current date, so the draw sequence stays current whenever the page is opened.