Migrate from WinQS to QSNAPP

In-depth guide to importing a WinQS project library (.WCLIB) into QSNAPP — grounded in confirmed schema behaviour from real restored project databases, not the empty staging tables the schema appears to advertise.

Overview

WinQS stores a full quantity-surveying project as a SQL Server database packaged inside a .WCLIB archive. QSNAPP can ingest that library and map the real QS artefacts your practice already uses: elemental Bills of Estimates (BoE), trade Bills of Quantities (BoQ), DimX takeoff batches, variation orders, and JBCC certificate history.

This guide documents the confirmed import path — reverse-engineered from restored project databases (including a full measured project with DimX batches, BoE, BoQ, issued certificates, VOs, and recovery statements). Where the schema and real behaviour disagree, this guide follows the data.

Source of truth

Findings here align with QSNAPP's qs-brain vault (knowledge/qs-brain) and the WinQS import forward plan (knowledge/WINQS_IMPORT_FORWARD.md). Treat claims as confirmed only when they cite real tables, row behaviour, or workflow steps from that research.

Prerequisites

  • A WinQS project export as .WCLIB (or an extracted .bak / CSV fixture pack for testing).
  • A QSNAPP project with permission to run imports.
  • A clear first import slice (DimX-only, BoQ, BoE, or certificates) so you are not forced to migrate the entire lifecycle on day one.
  • Awareness of the guardrails — especially decoy fields like item.vono.

What a .WCLIB contains

A .WCLIB file is a 7z archive, not a proprietary opaque blob. Inside you will typically find a SQL Server backup (.bak) that is the actual project database.

.WCLIB (7z archive)
  └── <project>.bak          # SQL Server database backup
      └── 78+ tables / views # structure, item, dimension, certificates, …

Confirmed research databases used to validate this guide include a full measured construction project (BoE, BoQ, DimX, multiple JBCC certificates, variations, recoveries) and a preliminaries-only contrast case. The import path does not require shipping SQL Server into the QSNAPP production runtime — ETL / offline restore / fixture packs can feed the mapper.

Import pipeline

End-to-end flow from library file to QSNAPP entities:

  1. Ingest — accept the .WCLIB, unpack with 7z, locate the .bak.
  2. Materialise — restore offline (lab) or load from pre-exported CSV fixtures for the tables you need.
  3. Classify by doctype — walk structure filtered by doctype (E / Q / X / G / J).
  4. Map the measurement chain structure → item → dimension → itemloc → itemprice.
  5. Attach provenance — DimX batches via extimport / extimportlink.
  6. Validate against guardrails — refuse decoy sources; verify quantities and certificate math on a sample before full cutover.
# Conceptual pipeline (lab / ETL — not the Next.js request path)
unpack(.wclib)
  → find(.bak)
  → materialise(tables)
  → map(structure[doctype], item, dimension, itemloc, itemprice)
  → link(extimport → extimportlink → item)
  → validate(guardrails)
  → write(QSNAPP project schema)

Document types (structure.doctype)

WinQS reuses the same measurement tables for different documents. The split is structure.doctype. Never merge these into one bill without an explicit re-home step.

DoctypeDocumentQSNAPP intent
EBill of Estimates (elemental cost plan)Map to elemental estimating / AAQS-aligned sections
QBill of Quantities (trade-measured contract bill)Map to BoQ structures; keep Model Preambles / H1–H4 / TX rows
XDimX / DimensionX takeoff landing zoneImport as measured, unpriced lines; price later
GGeneral-purpose constants (GPC structure)Import named constants as reusable factors — not via empty gpconstant
JJBCC / contract-admin related structureBring in with certificate / valuation slices

The measurement chain

Every measured item — manual or DimX — ends in the same doctype-agnostic chain. This is the load-bearing abstraction for the importer:

structure          # bill / section tree (parentstructureno)
  → item           # heading (H1–H4), text (TX), or measured line
    → dimension    # takeoff: dimqty1-3, dimexpr, dimtotal (+ vono for VOs)
      → itemloc    # item × location → measqty / valqty (ties to dimtotal)
        → itemprice # rate from price / pricegroup (may be empty on DimX)
  • Headings and preambles are items too unittype with measflag=0 (H1H4, TX, FF, ST) sits interleaved with measured rows.
  • Measured units use measflag=1 types such as M, M2, M3, NO, T, ITEM, %IT(percentage-of-items / builder's work allowance).
  • Secondary classification via keytypekeydesc itemkey is independent of structure placement. Do not assume setting one sets the other.

DimX (DimensionX) imports — how they really work

Critical: ignore the empty staging table

SpoormakerDimXItems looks purpose-built for BIM/takeoff import (and stored procedures reference it), but on confirmed real projects it can be completely empty. The live path bypasses it.

Confirmed real behaviour:

  • Items are created directly on item with createuser = 'dimX' (a sentinel, not a human login), often in a sub-second timestamp burst.
  • They land under a dedicated structure: doctype='X', structuretype='B', description along the lines of dimensionX.
  • Batch metadata lives in extimport (filename, import date, named operator, revision, Merged flag, project name). Links use extimportlink.winqslinkno = item.itemno.
  • Imported items are measured but not priced itemloc / dimension populated; itemprice empty. Treat rate application as a separate follow-up in QSNAPP.
  • item.vono = -1 on DimX items is a DimX sentinel, not a variation reference.

After import into QSNAPP you must still decide the document target when leaving the DimX zone:

  • Early design / composite costs → re-home into BoE (E) using AAQS element naming.
  • Tender / contract detail → re-home into BoQ (Q) using Standard System / Model Bills trade order.

BoE vs BoQ — keep them separate

Both share the measurement chain; they are different documents. Confirmed practice on real WinQS projects:

AspectBoE (E)BoQ (Q)
PurposeElemental cost planningTrade-measured contract / tender bill
Section namingAAQS element names (by name, not numeric codes)Standard System / Model Bills trades
PreamblesGenerally absent / elemental composite wordingModel Preambles for Trades + SUPPLEMENTARY PREAMBLES (TX / H2 / H4)
Typical contentComposite / provisional costs early onDetailed measured items per trade

Do not mis-attribute

Unscoped queries that ignore doctype will mix BoQ preamble text into BoE results. Always filter by doctype before mapping into QSNAPP modules.

Choose an import slice

You do not need a big-bang migration. Pick the slice that unlocks the next workflow, then expand.

SlicePrimary tablesOutcome in QSNAPP
DimX measured itemsstructure(X), item, dimension, itemloc, extimport*Takeoff lines ready for pricing / re-home
BoQ structure + itemsstructure(Q), item, dimension, itemloc, itemprice, unittypeTrade bill with headings and rates
Elemental BoEstructure(E), item, … (+ constants / %IT)AAQS-aligned cost plan
Certificates & VOsvariation, dimension.vono, itemlochistory, ccrcert, …JBCC valuation / payment history

Field mapping (WinQS → QSNAPP concepts)

WinQSMaps toNotes
structure + parentstructurenoBill / estimate section treeFilter by doctype first
item + unittypeLine (heading, text, or measured)Preserve H1–H4 / TX order
dimensionTakeoff / measurement rowsVO tag = dimension.vono
itemlocLocation quantitiesmeasqty should tie to dimtotal
itemprice / price / pricegroupRatesOften empty on DimX imports
extimport / extimportlinkImport batch provenancePrefer over SpoormakerDimXItems
keydesc / itemkeySecondary trade / activity tagsIndependent of structure
variationVariation order registerNot AuthorisedVariations alone
itemlochistoryCertified snapshotsNot CalculatedItemHistory
ccrcert / ContractorCertificatesCertificate values & paymentsPay the marginal amount

Guardrails — do not trust these

Copy this checklist into any importer review. Every entry is confirmed against real project data.

Do not use as source of truthUse insteadWhy
item.vonodimension.vonoDimX sentinel (often -1), not VO tracking
SpoormakerDimXItemsitem + extimport*Staging table can be unused entirely
CalculatedItemHistoryitemlochistoryLarge row counts can be empty scaffolding
Contractorscontractor → PersonsLegacy capitalised table often empty
gpconstantItems under doctype G structureReal GP constants live as bill items
AuthorisedVariationsvariation + dimension.vonoManual override, not full VO register
ccrcert.certvalue aloneMarginal payment (vs previous)certvalue is cumulative
ccrcertno = 0Filter outSynthetic pre-certificate baseline

Variation orders

To migrate VOs correctly: create / import the variation register, then ensure every affected measured row carries dimension.vono for that variation.

  • Finding what variation N changed → filter dimension on vono, never item.vono.
  • Financial impact signature → growing gap between ccrcert.contractvalue (original sum) and ccrcert.efcvalue (estimated final cost).
  • A VO record existing does not mean it is certified yet — certification flows through itemlochistory at a certificate.

Certificates and payment

When importing contract administration history:

  1. Snapshot source = itemlochistory (per item, location, certificate): pvalqty × itemprice.
  2. Roll-up ties to ContractorCertificates.WorkExecuted ccrcert.certvalue (allow small rounding via CertificateDecimals).
  3. Amount payable this certificate = marginal difference vs previous (PreviousCertificate when present).
  4. Retention is a named Recordsline (e.g. RecordTypeEnumId=4 "10%" / "7.5%"), not a hidden constant for the whole contract.
  5. Audit trail = merge JbccHistory with projecthistory (lock/unlock entries name certificate numbers).

Escalation caveat

Haylett escalation may run and produce populated rows while still paying R0 on every row. Always check amounts — do not treat presence of escalation records as proof of a claim.

Validation checklist

Before treating an import as production-ready:

  • Row counts for chosen doctypes match source (structure sections, items, dimensions).
  • For a sample measured item: itemloc.measqty equals dimension.dimtotal.
  • DimX batches: provenance present; itemprice empty expected; createuser sentinel understood.
  • No importer logic reads item.vono for variations.
  • BoE and BoQ section trees imported under separate document roots.
  • If certificates imported: exclude ccrcertno=0; spot-check one certificate's marginal payment.
  • Print/heading order preserved for a trade section (H1→H4→TX→measured).

Troubleshooting

SymptomLikely causeFix
No DimX rows found in SpoormakerDimXItemsTable unused on this projectQuery item where createuser='dimX' + extimport*
BoE full of Model Preambles textQuery not filtered by doctypeRestrict to doctype='E' vs 'Q'
Variation report returns DimX itemsFiltered on item.vonoUse dimension.vono + variation table
Certificate 'amount due' looks hugeReported cumulative certvalueSubtract previous certificate / PreviousCertificate
GP constants missingLooked in gpconstantLoad doctype='G' structure items
Contractor names blankJoined Contractors (legacy)Use contractor.PersonId → Persons

Next steps

  • Open the product page: Switch from WinQS
  • Start a QSNAPP project and prepare your first slice: Sign up
  • For agent / lab workflows, query qs-brain locally:
    cd qsnapp-web/knowledge/qs-brain
    graphify query "how does DimX import work?"
    graphify explain "measurement chain"