02 — Module-by-Module Test Charter¶
Your prioritized test plan for the July pilot. Modules are ordered roughly by pilot importance and by the order work flows through the product. Each module gives you: what it does, the happy path (the "it works" walkthrough), high-risk edge cases (where bugs hide), role/permission checks, and data-integrity checks.
Scope legend ✅ JULY — in the pilot; test it hard. 🟡 PARTIAL — core works, but pieces are September; test the July pieces only. 🚫 SEPTEMBER / NOT BUILT — do not file functional bugs; it's unbuilt or being redesigned. Note ideas for the backlog instead (see doc 04).
Two standing reminders that apply to every module below: 1. Field-level financial masking is NOT in July. A role seeing a money field it "shouldn't" (per the intended rules in doc 01 §2) is not a July bug. Module-level access (can you open the area at all) and Add/Edit/Delete button gating are testable. 2. Money fields are large integers. Watch for wrong currency formatting, rounding errors, negative/overflow behavior, and blank vs.
$0— these are classic, high-value bugs.
Priority 1 — Bids & Bid Invites ✅ JULY (most mature module, ~90%)¶
What it does: The front door of winning work. Bid Invites come in (often synced from BuildingConnected/Procore); Pinley accepts one, which creates a Bid; the Bid moves through a forward-only status pipeline and carries documents, vendors, an estimate, and an outcome.
Happy path:
1. Open Bid Invites (/bid-invites). Accept an invite → it produces a Bid (assign to an estimator).
2. Open the Bid (/bids/:id) → Overview shows GC/client, location (map), estimated value.
3. Move the bid forward through statuses (New → Qualifying → Estimating …).
4. Award it (→ becomes a project) OR mark it Lost / No-Bid / Withdrawn with a reason.
High-risk edge cases: - Forward-only status — try to move a bid backward in the pipeline; it must be rejected. Try to change a bid that's in a terminal state (Awarded/Lost/etc.); that should also be blocked. - Lost / No-Bid / Withdrawn each open a modal that requires a reason. On Lost to a competitor, the competitor field appears — confirm the outcome (reason, competitor, final vs. submitted price) is captured and shown on the Overview afterward. - Sync from BuildingConnected/Procore — run a sync; confirm "Last synced X ago" timestamp updates and survives a page refresh. Sync twice — no duplicate bids/invites. - Drawings upload works both before acceptance (uploads to the invite) and after (uploads to the bid). - Long GC/vendor/client names in dropdowns and cards — do they truncate cleanly or break layout?
Role/permission checks: Estimating category = full; PM/Senior PM/Assistant PM = read; Field/Compliance = no access. Confirm the Bids nav item is hidden for Field. Accept-modal "assign to" list should be limited to estimating roles.
Data-integrity checks: Estimated/contract amounts format as currency correctly. Awarding a bid must create exactly one project and one (initially empty) bid outcome record. Status changes should appear in the activity/audit trail.
Priority 2 — Estimating / Estimate Sheet ✅ JULY (with 🚫 AI-ingestion caveat)¶
What it does: The spreadsheet-like heart of pricing a bid — sections, line items, sub-lines, vendor-quote columns, markups, tax, insurance, overhead, contract price. Supports undo/redo, revisions, AI scope extraction, and Excel/CSV import.
Happy path:
1. From a bid, open the Estimate (/bids/:id/estimate). Add sections and line items; enter quantities and vendor quotes.
2. Watch totals/footer (markup %, tax %, overhead %, contract price) recompute.
3. Save a revision; keep editing; compare against the earlier revision.
High-risk edge cases: - Undo/redo — make several edits (including footer % changes), undo repeatedly, redo. Do totals and footer values restore correctly and consistently (not "some fields revert, others don't")? Refresh the page after undo — did the DB actually save the undone state? - Empty/zero values — empty line item, quantity 0, empty estimate, deleting the last section. No crashes; totals stay sane. - Excel/CSV import — import a large sheet (hundreds/thousands of rows), a sheet with merged cells, a sheet with unknown trades, subtotal rows. Confirm the preview warns appropriately and the import doesn't freeze or drop rows. Try "Append" vs "Update" modes. - Concurrent editing — two users (two browser sessions) editing the same estimate; do changes collide or one silently overwrite the other? (There's a live-presence feature — check it shows the other user.) - Big numbers — very large contract values; correct formatting, no rounding/overflow surprises. - Equipment deletion — delete an equipment line with live and previously removed vendor quotes. The selected line and only its attached quotes should be removed; other equipment rows and their quotes must remain intact. - AI scope extraction with no results — run extraction with no eligible PDFs, oversized documents, or failed downloads. The backend's specific explanation must appear as visible feedback instead of the Run AI button silently resetting.
Role/permission checks: Estimating + Executive/Owner = full; most others = none. For a read-only PM, confirm the main grid, Equipment, Takeoff, templates, and Proposal generation are all non-writable. No write RPC should be attempted and no permanent permission failure should enter a retry loop.
Data-integrity checks (high value): - Revision immutability (doc 01 §5): create a revision, note its numbers, then change the live estimate, then re-open the old revision — old numbers must be preserved (including snapshot tax/insurance/overhead %). - "Edited by {name} · {time}" tracking and AI-generated (✦) markers show on the right rows.
🚫 SEPTEMBER within this module: AI ingestion of estimate spreadsheets (importing/parsing external estimate xlsx via AI, "TruncTools"-style) is a September spike — not built. Don't test it.
Priority 3 — Projects & Project Detail ✅ JULY¶
What it does: The awarded-job workspace. /projects lists projects; /projects/:projectId/detail is a tabbed detail page hosting most execution modules (Overview, Budget, Spec Sections, Field → [Progress / Daily Logs / Punch List / Reports], Submittals, RFIs, Change Orders, Billing/SOV, Documents).
Happy path: Open a project → walk each tab → confirm data loads and the tab's own module works (the modules themselves are Priorities 4–7 below).
High-risk edge cases: - Tab navigation — switching tabs, deep-linking to a tab URL, browser back/forward. Some sub-views (submittal detail vs. log, RFI create vs. list) are internal view-switches with no URL — back button may behave oddly; note real dead-ends. - A brand-new project (no daily logs, no RFIs yet) — every tab should show a clean empty state, not an error. - Mobile / narrow window — the tab strip should scroll, not clip tabs off-screen.
Role/permission checks: - PM category = full projects; Field = read; Estimating = read/none. - Budget tab is intentionally hidden from Assistant PM (a deliberate product decision). So an Assistant PM not seeing the Budget tab is correct behavior, not a bug. Every other internal role sees it. - The map, quick actions, and org links on Overview render for the right roles.
Data-integrity checks: The project's linked parties (GC, client, property manager, owner's rep) and address match what the awarded bid had. Contract value carried over from the bid.
Priority 4 — Daily Logs ✅ JULY (recently reworked — test carefully)¶
What it does: Field crew records each work day: manpower (trade + # workers + hours), materials, delays, safety, photos, and free-text "work performed." A day is a Draft until Completed, which locks it. Recently rebuilt (the Submit/Approve flow was replaced by "Complete Work Day").
Happy path:
1. Open a day (from /daily-logs or the project Field tab). Add manpower rows (pick a trade, enter workers/hours), materials, delays, safety, work performed.
2. Complete Work Day → the day locks, showing who completed it and when.
3. A permitted role Reopens it → editable again.
4. In Reports sub-tab: pick a date range + category, export PDF (full report) or CSV (one category).
High-risk edge cases (there was a real data-loss bug here — probe hard): - Data loss: enter manpower, then type in "Work Performed," then blur/save — the manpower must NOT get wiped. (This was a fixed bug; regression-test it.) - Complete gating: completing should require at least one manpower row + non-empty work performed. Try to complete an empty day — should be blocked. - Lock enforcement: after Complete, all child sections (manpower/materials/delays/safety/photos) must be read-only. Try editing anyway. - Reopen role-gating: Reopen is limited to Owner/Exec/PM/Assistant PM/Superintendent. A Field User or Senior PM should NOT see/succeed at Reopen. Verify per role. - Trades dropdown must list the 18 field-labor trades (Sheetmetal, Pipefitter, Insulator, Plumbing, Electrical, Fire Protection, Fire Alarm, Carpentry, Controls, Technician, Painter, Glazier, Roofer, Mason, Ironworker, Laborer, Rigger, Operating Engineer) — NOT the big estimating trade catalog. Worker/hour inputs reject negatives. - Calendar bulk-complete multiple days at once; already-completed days are skipped, not double-processed. - Export edge cases: empty date range (valid — should succeed with an empty report, not error); a range spanning many days; special characters in notes (accents, em dashes, commas) shouldn't corrupt the PDF/CSV. CSV must require a single category.
Role/permission checks: Field = full daily logs; PM category = full; Compliance = read; Estimating = none. Export buttons gated on the export permission.
Data-integrity checks: Completed-by name + timestamp are accurate. PDF header shows correct project name + number. CSV values match on-screen values. Photos in the PDF appear (or list filenames) without breaking.
Priority 5 — RFIs ✅ JULY (+ PDF export, recently added)¶
What it does: Formal questions to the GC/architect. Status lifecycle: Draft → Open → Sent → Answered → Closed (every RFI starts as a Draft; "Send" emails a PDF to the recipient and moves the ball to their court; the response is then logged in-app). Create form auto-suggests an RFI number and a due date; single RFIs and the RFI log export to PDF. Lives under Project Controls → RFIs (next to Submittals). (Corrected 2026-07-08 against the code — full click-by-click in the RFIs walkthrough.)
Happy path: 1. In the project's Project Controls → RFIs sub-tab, create an RFI (subject, question, trade, cost/schedule impact, due date) — it saves as Draft. 2. Send it (picks an organization + contact, emails the PDF, → Sent) → Log Response (→ Answered) → Close. 3. Export a single RFI to PDF; export the whole RFI log to PDF.
High-risk edge cases:
- RFI number field pre-fills as RFI-NNN and is editable but the backend auto-assigns the real number at submission — confirm no duplicate/skipped numbers when several RFIs are created quickly.
- Due date defaults to today + 5 business days (skips weekends) — spot-check the math around a weekend.
- Status transitions — only valid moves allowed; can't skip or reverse illegally.
- PDF text — put an em dash, curly quotes, accented characters, and a very long question in an RFI; the PDF must render them as readable text, not garbage. (fpdf uses Latin-1; this was a real bug class.)
- Trade dropdown shows full trade names, not truncated.
- Empty RFI log → "Export Log PDF" should produce a valid (empty) PDF, not crash.
Role/permission checks: PM category = full; Estimating = read; Field/Compliance = limited/none. Export buttons gated on permission.
Data-integrity checks: Status changes fire notifications to the right roles and appear in the audit trail. Cost/schedule impact values persist and display.
Priority 6 — Submittals ✅ JULY (+ Spec Section / Cost Code data model)¶
What it does: Product/material approval packages sent to the architect. Each carries a spec section (CSI number) and cost code, a responsible vendor, "received from"/"submit by" people, and a decision (Approved / Approved as Noted / Revise & Resubmit / Rejected).
Happy path: 1. Create a submittal (title, spec section, responsible vendor, submit-by member). 2. Edit it to set the cost code (cost code is edit-only by design — it's not on the create form; that's intended). 3. Record a decision; confirm it shows in the log and detail views.
High-risk edge cases: - Spec section picker: when the project has spec sections defined, it's a dropdown; when it doesn't, it falls back to a text input. Test both. - Responsible vendor displays correctly (nested org name shows, not blank). - Received From / Submit By are member dropdowns (people), not free text — verify names show in log/detail. - Long spec-section/vendor names truncating in the create modal.
Role/permission checks: PM category = full; Estimating = read; Exec/Admin = read; others = limited/none. Spec Sections management tab in Project Detail is gated on the spec-section permission.
Data-integrity checks: Decisions fire notifications to PM roles. Cost codes come from the seeded CSI list (Divisions 21/22/23/25/26). Note: the exact cost-code list is still pending final client confirmation — if the codes look "wrong," that may be a seed-data question for Marko, not a bug.
Priority 7 — Change Orders & Proposals ✅ JULY¶
What they do: Change Orders (COs/PCOs, plus the more specialized ICO and Backcharge types) capture post-award scope/price changes, with PDF/image attachments and a PDF export. Proposals are the formal priced offer sent to the client pre-award, generated as a PDF from a frozen estimate snapshot.
Happy path (Change Orders): In a project's Change Orders tab, create a CO → attach a PDF/image → see the attachment count badge on the log → open it, preview inline, download → export the CO to PDF.
Happy path (Proposals): From a bid, add a proposal revision (snapshots the estimate totals) → generate the proposal PDF → confirm it reflects the snapshot, not later live edits.
High-risk edge cases: - PDF export for Change Orders and Proposals now uses the production-safe pure-Go renderer (converted from Chromium in PIN-504), same as Daily Log and RFI. All PDF exports should work on staging/production — failures there ARE bugs. - Attachment handling — attach a non-PDF/non-image, a very large file, a file with a weird name; inline preview vs. forced download; deleting an attachment updates the count badge. - Proposal immutability (doc 01 §5): generate a proposal, then change the underlying estimate, then regenerate/re-open — the proposal must reflect the frozen snapshot, not the new estimate data. - New CO appears in the log immediately after creation (no manual refresh needed).
Role/permission checks: Change Orders: PM tier (Assistant PM / PM / Senior PM) plus Owner/Admin/Exec can create; Estimating roles (including Chief Estimator) are read-only, not create — this corrects an earlier version of this doc; Finance = read. Proposals: Estimating + Exec/Owner.
Data-integrity checks: CO amounts format correctly and roll into project totals. Proposal PDF numbers equal the estimate snapshot at revision time.
Priority 8 — Login (Cara Vault) ✅ JULY (rebuilt for launch)¶
What it does: The entry point. Rebuilt for launch with the new Cara brand ("Cara Vault" login — tokens, typography, favicons, marks). The login is fully Cara-branded (Cara mark top-left, "Pinley Mechanical" appears as the workspace name and in the secure-access strip — there is intentionally no Pinley logo); no vendor branding on the login. Errors show as inline banners, not toasts. (Updated 2026-07-08 to match the shipped Vault — see the Login walkthrough.)
Happy path: Log in with valid credentials → lands in the app. Log out → redirected back to login. Wrong password → clear error. Forgot/reset password flow. "Remember me"/session persistence across refresh.
High-risk edge cases: - Invalid credentials, empty fields, locked/inactive user, expired session/token (leave a tab idle, then act — are you cleanly bounced to login?). - Branding correctness (this is a recent visual rebuild) — logo placement, no stray vendor branding, correct typography/marks. Visual bugs here ARE worth logging since it's launch-facing and just changed. - Deep-link while logged out → after login, do you land where you intended or on a default page?
Role/permission checks: After login, the sidebar/nav must reflect the logged-in role (a Field User shouldn't see Bids, etc.).
Priority 9 — Cara Copilot & Hub ✅ JULY (widget + Hub redesign shipped; 🚫 Tasks/email deferred)¶
What it does: Cara is the AI assistant. Two surfaces: a floating widget (draggable, remembers position, page-aware) available across the app, and a full-page Hub (/cara) with a welcome screen, a conversations sidebar, and action cards. Cara can answer questions and generate documents; on awarded bids it can generate the SOV.
Happy path: 1. Open the floating Cara widget on a bid/project page → ask a question → get a page-aware answer. 2. Open the full Hub → start a new conversation from the welcome screen or an action card → converse. 3. On an awarded bid's SOV tab → "Generate SOV with Cara" → review the proposed line items → approve when balanced.
High-risk edge cases: - Page awareness — on a specific bid/project, does Cara actually know which one you're on? Navigate away — does context reset correctly? - Widget — drag it around, reload the page (position should persist), reset-to-start; open/close toggling. - SOV generation — the proposed SOV must sum to the contract amount. Approval must be blocked unless the SOV is balanced (a "balance" chip shows over/short). Try approving an unbalanced SOV — should be rejected. - Conversations — the sidebar shows conversations; empty state ("No conversations yet") for a fresh user; starting from an action card should carry the prompt into the new thread. - Budget cap — Cara has a per-user monthly spend cap; heavy use should hit a graceful "budget exceeded" state, not crash. - Markdown/tables in Cara's answers render cleanly.
Role/permission checks: Most roles get Cara (read/full); Field/Compliance = read. SOV write (generate/approve) is gated to estimating/PM roles.
🚫 SEPTEMBER within Cara: Cara × Tasks (task management + Cara-driven task creation) and the email-to-task integration are September / a private module for Conor — not built into the pilot. Don't test them.
Priority 10 — SharePoint Import & Sync ✅ JULY (shipped — test it for real now)¶
Status update: this used to say "not built yet, don't test it." That's no longer true — the import and sync now work end to end. Test this module like any other July-scope feature.
What it does: Pinley's real bid/project documents live in SharePoint. Cara imports them so a Bid or Project's Documents tab shows the same files without anyone re-uploading by hand. A button on the Bids list (for bid folders) or the Projects list (for project folders) triggers a sync — running it again picks up anything new or changed in SharePoint without creating duplicates.
Happy path: 1. On the Bids list or the Projects list, trigger a SharePoint sync for a record that has a matching SharePoint folder. 2. Once it finishes, open that Bid/Project's Documents tab — the files from SharePoint appear, sorted into the right folders. 3. Run the sync again — no duplicate files, nothing lost.
High-risk edge cases:
- Files with unusual names, deep folder paths, or special characters — do they come in with correct names?
- Re-running the sync after files changed in SharePoint — updates show correctly, nothing duplicated.
- A shared SharePoint link that mixes bid folders and project folders — each file should land under the right one (Bid vs. Project), not mixed up.
- A large document set — the sync should finish cleanly, not time out or silently skip files.
- A project folder containing Submittals or Shop Drawing — package files should appear in Project Controls → Submittals, not P8 Reference & Support. Files in the same specific package subfolder should group under one Submittal even when their filenames do not repeat a number.
- Numbered module folders such as RFI #07, CO#01, or S-014 — a file whose own name omits that number should still attach to the same RFI, Change Order, or Submittal as its numbered siblings, not create a duplicate module record.
- Creating a brand-new project from SharePoint — Project Manager should remain unassigned until someone explicitly selects a real PM; it must not silently show the seeded admin/system user.
Role/permission checks: Triggering a sync requires the SharePoint import permission — confirm the button is hidden or blocked for roles that shouldn't be able to kick off a company-wide import.
Data-integrity checks: Every imported file should land in a sensible physical folder or the correct workflow module, not a generic catch-all. Folder-derived module numbers must be preserved for grouping, and no file should vanish or duplicate its module record after a second sync run.
🚫 SEPTEMBER within this area: Automatic, real-time two-way sync (editing a file, either side, and having it reflect instantly both ways) is still September scope. For July, "sync" means someone clicking the button — that's expected, not a workaround.
🚫 September Scope — do NOT file functional bugs against these¶
These are either not built yet or are being actively redesigned for the September rollout. If you spot something, capture it as a backlog idea (target-sep), not a launch-cycle bug (see doc 04). Confirm with me or Marko if unsure.
- Full-page redesigns: Vendor list, Client list, Bid Overview, and Project Handoff pages are being redesigned from new client mockups (mockups not yet delivered). The current versions work but will be replaced — don't polish-bug them.
- AI estimate ingestion (parsing external estimate spreadsheets via AI).
- Bidirectional SharePoint sync + the "Sync now" UI.
- Full 13-role RBAC matrix + admin permission-editing UI.
- Field-level financial masking / budget confidentiality (PMs not seeing profit, etc.) — the enforcement layer is September.
- Cara × Tasks and email-to-task AI integration.
- Insurance / COI / Compliance module — deprioritized and largely deferred; not a pilot focus. (The immutability rules in doc 01 §5 still apply anywhere revisions appear.)
- Advanced drawing/takeoff features and the new drawing color scheme redesign.
Suggested first-week testing order¶
- Login (Priority 8) — you need it to do anything; and it just got rebuilt.
- Bids & Bid Invites (Priority 1) — most mature; good place to learn the app's patterns.
- Estimate sheet (Priority 2) — high-value integrity target (revisions, undo/redo, money).
- Daily Logs (Priority 4) — recently reworked, known past data-loss bug; high pilot use by field.
- Projects → RFIs → Submittals → Change Orders (Priorities 3, 5, 6, 7) — the execution modules.
- Cara (Priority 9) — cross-cutting; test as you go. SharePoint sync (Priority 10) is also live now — worth a pass once you've covered the modules above.
Log everything per doc 04. When you're unsure "is this a bug or intended?", use doc 03.