A client-only tool for WFRC to score and rank RFP proposals — configurable firms, reviewers, weighted criteria, and scoring scale, with an Excel-based round trip for collecting reviewer scores and a print-quality PDF report for the official procurement record.
No backend, no database, no accounts. Everything runs in your browser. The only
durable save is a project.json file you explicitly download and later re-open — there is
no server-side storage of any project data, ever (see Constitution
Principles I/II/IV).
- Load — start a new project, or upload a previously exported
project.json. A file with scores already in it goes straight to the Dashboard; an in-progress file resumes in Configuration. - Configuration — set up project info, firms (invited/submitted, picked from a searchable/creatable name list), reviewers (TLC Applicant or WFRC), weighted criteria (weights entered as a decimal or a percent, your choice), and the scoring scale (a fixed set of discrete points, or a continuous range like 1.0–5.0). Export the JSON at any point.
- Reviewer Forms — generate a real
.xlsxscoring workbook per reviewer (one button, or "download all" as a single.zip). Reviewers fill it in Excel/Sheets/LibreOffice — they never need to know this app exists. Import the completed workbooks (one at a time or in bulk) to populate scores, or enter scores manually for anyone who reported back by phone/email. - Dashboard — a sortable, per-row-expandable ranked firms table (Overall, TLC
Applicant-only, and WFRC-only weighted totals, each its own rank lens), per-firm
criterion-breakdown and reviewer-score-spread charts, a full "show calculations" audit
trail (every raw score and derived number, traceable back to its formula — nothing is a
hardcoded snapshot, including in the
.xlsxexport), and PDF/JSON export.
The full data model, calculation rules, and file-format contracts live in
specs/001-consultant-selection-scoring/ —
spec.md for requirements, data-model.md for the schema, and contracts/ for the
project.json and reviewer-workbook formats. (The spec folder and the package.json name
predate the "Proposal Evaluation Scoresheet" rename and still say "consultant-selection-
scoring" — an internal/historical label only, not user-facing.)
npm install
npm run dev # start the Vite dev server
npm run test # run the test suite (Vitest)
npm run lint # ESLint
npm run build # production build -> /docsRequires Node.js 20+.
tests/unit/— pure-logic tests (the calculation engine, schema validation, contrast ratios) with no React or DOM involved.tests/integration/— ExcelJS generate/parse round trips. Some run under Vitest'snodeenvironment rather than the project default (jsdom) — see the file-level comments; it's becauseBlob.arrayBuffer()andFileReaderaren't both available in either single environment, and each test picks whichever one it actually needs.tests/component/— full app-flow tests using React Testing Library, exercising real generated/parsed.xlsxdata (not mocks) through the actual rendered UI.- Opening a generated reviewer workbook in real Excel (not just re-parsing it with
ExcelJS) is a manual step no automated test can substitute for — see
specs/001-consultant-selection-scoring/qa-signoff.md.
No CI/CD — deployment is a manual, local build-and-commit, published via GitHub Pages
"Deploy from a branch" (main / /docs):
npm run deployThis runs npm run build (which writes straight into the tracked /docs folder — that
is the deployed site, not a build-scratch directory excluded from git) and then prints a
reminder of the remaining manual steps:
git diff --stat docs/ # sanity-check the diff actually reflects your latest build
git add docs/ <your source changes>
git commit -m "..."
git push # this is what actually publishes — GitHub Pages picks it upSee specs/001-consultant-selection-scoring/research.md §9 for the full rationale
(no CI, no build server — whoever pushes to main with an up-to-date /docs is the
deploy step).
Visual identity (colors, typography, logo) is sourced directly from the WFRC brand
repository, not invented — see
specs/001-consultant-selection-scoring/research.md §10 for the exact fetched values and
src/theme/tokens.css for how they're applied, including the accessibility-driven
adjustments (documented inline) needed to meet WCAG 2.1 AA in both light and dark mode.
Charts use that same palette for their data-series colors (never invented hex values), with
a fixed WFRC = blue / Overall = orange / TLC Applicant = green convention throughout.
Scores and comments are procurement-sensitive. This app never calls any external API with
project data — the only network requests the app itself makes are static Google Fonts CDN
requests for font files, carrying no project content. See
specs/001-consultant-selection-scoring/qa-signoff.md (T051) for a full audit.
Ideas raised internally for where this tool could go next, if the underlying architecture ever changes to support them — captured here so they aren't lost, not a roadmap or a commitment:
- A disclaimer / non-disclosure form reviewers acknowledge before they can see or score a proposal.
- Letting the TLC applicant fill out their own submission online, instead of the current offline-proposal-plus-Excel-scoring-workbook flow.
- A full pipeline: sign in → accept disclaimer → get access to the proposal → score it → submit — replacing today's "generate a workbook, email it, import it back" exchange.
- Real firm information (contact details, website, etc.) pulled automatically from a firms database, instead of today's static name-only list.
- Email notifications to reviewers (e.g. "you have a new proposal to score," reminders for outstanding scores) instead of the current manual "hand them a file" workflow.
- Integrating with WFRC's Google Workspace/organization APIs — e.g. writing scores into a Google Sheet — as a possible lighter-weight alternative to standing up a dedicated backend/database for any of the above.
Every one of these requires a real backend, a firms database, and/or a third-party
integration — accounts, authenticated access control, and server-side (or third-party)
storage of procurement-sensitive material — which is the opposite of this app's current,
deliberate design (see Constitution Principles I/II/IV above, and Privacy above): no
accounts, no server, no data ever leaving the browser except as a file the user explicitly
downloads. That trade-off is why privacy is currently a non-issue here: there is nothing
to breach, because nothing is stored or transmitted anywhere. Taking on any of the above
would mean deliberately giving that up in exchange for new capability, and reopening real
questions that don't have answers yet — who hosts it and pays for that hosting, who is
responsible for its security and uptime, how reviewer/applicant identities are verified,
how long submitted data is retained and who can access it, what happens to that data if the
hosting arrangement ever ends, and — for any third-party integration (Google Workspace or
otherwise) — whose account owns that data, what that provider's own access/retention terms
are, and whether routing procurement-sensitive scoring data through an external API is
acceptable at all. None of that is designed yet; this section exists so the trade-off is
visible before anyone starts building toward it. A dedicated follow-up discussion is
expected before any of this moves forward.