Skip to content

v1.0.0 — ScopeMaker

Choose a tag to compare

@ibuilder ibuilder released this 07 Aug 06:27
· 28 commits to main since this release
36a3042

Construction scope of work exhibits, generated properly.

📖 Documentation · Deployment · API · Clause library


This is a complete rewrite

The repository was previously a browser-only prototype that could not run: every page loaded js/procore-api.js, js/exhibit-generator.js, js/database-service.js and js/export-utils.js, and none of those files were ever committed. v1.0.0 replaces it with a Flask 3 application built around the part that actually matters — generating the scope, not the Procore connector.

Prototype v1.0.0
Does it run? ❌ Four referenced JS files never committed ✅ Flask 3, 9 blueprints, service layer
OAuth secret ❌ Browser localStorage ✅ Server-side only, Fernet-encrypted at rest
PDF export html2canvas screenshot on one A4 page ✅ WeasyPrint paged media, selectable text, Page N of M
DOCX export alert('would be implemented here') ✅ python-docx, formatting runs, live page fields
Scope content ❌ One hardcoded Fire Protection sample ✅ 236 clauses, 139 spec sections, 20+ trades
CSI divisions ❌ 16 hand-typed, several nonexistent ✅ Canonical MasterFormat 2020, reserved excluded
Storage ❌ Browser localStorage ✅ PostgreSQL, SQLAlchemy 2.0, Alembic
Accounts ❌ None ✅ Organizations, roles, invitations, OIDC SSO
Tests ❌ None ✅ 216 tests, CI on Python 3.11 and 3.12
Third-party JS ❌ 8 CDN <script> tags ✅ Zero — strict default-src 'self' CSP

What makes it useful

Cross-division specification references. A Division 21 fire protection package is automatically offered the Division 07 firestopping, Division 08 access doors and Division 28 fire alarm interface it is contractually responsible for. Missing those is where scope gaps come from.

Numbering that means something. Outline labels are computed once and written literally into every format, so clause 3.2.4 identifies the same sentence in the PDF, the Word file, the Markdown and the JSON.

Documents that survive review. Real paged PDFs with running headers, footers and page numbers, and text that is selectable and searchable. Word files you can redline.

Versioned and auditable. Issuing a scope freezes an immutable revision. Later edits create a new version, so what went out with the subcontract is preserved verbatim.

Getting started

git clone https://github.com/ibuilder/procore-exhibit-generator.git
cd procore-exhibit-generator
cp .env.example .env

python -c "import secrets; print('SECRET_KEY=' + secrets.token_urlsafe(64))"
python -c "from cryptography.fernet import Fernet; print('ENCRYPTION_KEY=' + Fernet.generate_key().decode())"

docker compose up --build
docker compose exec web flask create-user you@example.com --org acme --role admin
docker compose exec web flask demo-data --org acme

Important

Outside Docker, PDF export needs WeasyPrint's native libraries (Pango, cairo, GDK-PixBuf). Without them the app still runs and DOCX, HTML, Markdown and JSON all export — only PDF is disabled, and the UI says so. Run flask check-pdf to see where you stand; the deployment guide has the per-platform commands.

Security fixes

  • Removed the Procore client secret from browser localStorage, where any XSS could read it
  • Migrated off traditional Procore service accounts (retired 2025-03-18) to Developer Managed Service Accounts
  • Argon2id password hashing, hash-only API token storage, bleach allowlist sanitization
  • ALLOWED_HOSTS validation, open-redirect checks, bounded ProxyFix trust
  • Tenant isolation enforced in one place; cross-tenant access returns 404, not 403
  • Production config refuses to boot without secrets, and refuses SQLite

Breaking changes

Everything. There is no upgrade path from the prototype — it had no persistent storage to migrate. The static HTML files have been removed and the product is renamed ScopeMaker.

Full detail in CHANGELOG.md.


Not affiliated with or endorsed by Procore Technologies, Inc. CSI MasterFormat division titles are used for identification; the complete section list is published and copyrighted by the Construction Specifications Institute.