assessment-model/docs
Daniel Roth 4204b1fe0e feat(ara-projects): import — contractor/stage columns + setup gate
Extends the #414 upload-and-parse work (does not rewrite it) with a per-row
contractor, an optional stage, and a setup-completeness gate on the import
page. New ADR-0019 records the design. Still writes nothing.

CHANGE 1 — template + parser expected fields
  Final column order: Property identifier, Workstream, Contractor, Stage,
  Work order reference (optional), Forecast end date (optional). Contractor is
  required; Stage is optional (blank falls back to the workstream's first
  stage at commit). buildImportTemplateCsv, its worked example and the field
  docs are updated. The raw parser stays header-agnostic — required/optional is
  enforced in mapping (#415) and validation/commit (#417), not here — with a
  test proving a file missing the required Contractor column still parses.

CHANGE 2 — setup-completeness gate (the substantive feature)
  src/lib/projects/import/readiness.ts: a pure computeImportReadiness(facts)
  plus a read-only loadImportReadiness(projectId) round trip. Rule: every
  project_workstream must have >=1 project_workstream_stage AND >=1
  project_workstream_contractor, and the project must have >=1 workstream.
  Evidence requirements (#412) are advisory and excluded from the gate. The
  helper returns per-workstream detail (which are incomplete, and why) and is
  built to be reused by #413's final wizard step — noted in a comment.

  The import page loads readiness and, when not ready, renders an
  ImportSetupIncomplete state (lists the incomplete workstreams with the reason,
  links to project setup) instead of the drop zone — not a 404, not a silent
  empty zone. When ready, the drop zone renders as before. The gate applies on
  every entry: the route stays reachable standalone, and a comment notes #413
  will also route the wizard into it (that wiring is out of scope here).

CHANGE 3 — ADR-0019
  Records: import is the final, setup-gated wizard step; contractor is supplied
  per row and must match a contractor already assigned to the workstream
  (contractor creation is out of scope — the existing "invite company to Ara"
  flow owns it); stage is optional per row with first-stage fallback. States
  the trade-off vs the replaced #417 design, which derived the contractor from
  the workstream's single assignee — abandoned because
  project_workstream_contractor is a collection, so one workstream's properties
  can be split across contractors, which a single-assignee lookup cannot express.

Notes on the readiness query
  count(distinct project_workstream_stage.id) / (…contractor.id) over two left
  joins — the distinct is load-bearing because joining both children at once
  makes a stages x contractors cartesian product a plain count(*) would
  over-count. count(distinct) returns a bigint that node-postgres hands back as
  a string, so each count is coerced with Number(); a loader test drives a
  mocked db to prove that coercion.

Production-DB safety
  No migrations, seeds or writes. loadImportReadiness is read-only SELECTs and
  is not executed here. Unit tests mock @/app/db/db (vi.mock) and open no
  connection; the pure readiness logic is tested with in-memory fixtures.

Full suite: 575 passing. tsc and eslint clean. authz modules and
src/app/projects/page.tsx untouched (other branches own them).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 16:36:16 +00:00
..
adr feat(ara-projects): import — contractor/stage columns + setup gate 2026-07-22 16:36:16 +00:00
backend-asks feat(tags): table query + tag filter, filter-driven bulk assign, preview join, settings UI 2026-07-13 16:23:49 +00:00
design docs(design): home-page redesign context — Stitch refs, PRODUCT.md, impeccable trial 2026-07-07 15:12:07 +00:00
runbooks perf(backfill): faster, resumable recommendation denormalization + ops tooling 2026-07-02 10:00:46 +00:00
wip fix(postcode-search): PR #355 review feedback 2026-07-06 15:13:49 +00:00
wireframes/ara-projects Add Ara Projects UX wireframes under docs/wireframes 2026-07-20 15:15:21 +00:00