Fulcrum is a project and permitting management platform built by Odin Research for BFAM Builders. It manages the full lifecycle of QSR exterior remodel projects — from initial permitting through construction completion — and is deployed at:
What Fulcrum replaces
| Was | Now |
|---|---|
| Permitting_Workflow_Tracker.xlsx | Live task checklists per project |
| Email Transfer.xlsx | Site details, contacts, activity log |
| Teams threads | Structured notes + automated notifications |
| Manual status updates | Real-time dashboard |
| Shared SharePoint spreadsheet | Checkers read-only portal |
| Manual quote reformatting | Built-in quoting tool |
Project types
| Type | Description | Permits |
|---|---|---|
| Rere | Lights and minor changes | Electrical (sometimes), Mural (sometimes) |
| Remodel | Full exterior, 8-day crew | Building (stamped plans), Electrical, Mural |
Fulcrum is a monorepo where each component is named after a Rebel Alliance ship. Each ship has a single responsibility.
| Table | Description | Key fields |
|---|---|---|
sites | Physical locations | store_number, address, jurisdiction, portal_url, portal_username |
users | BFAM team members | email, display_name, role, azure_oid, is_active |
projects | Active jobs | site_id, project_type, status, is_archived, coordinator_name |
permits | Permit tracks | project_id, permit_type, status, permit_number |
tasks | Checklist items | permit_id, name, status, sequence, assigned_to_id, due_date |
task_dependencies | Task locking logic | task_id, depends_on_task_id, required_status |
task_status_history | Immutable change log | task_id, old_status, new_status, changed_by_id, changed_at |
contacts | AHJ and other contacts | site_id, project_id, name, phone, email, contact_type |
notes | Activity log | project_id, task_id, author_id, body, created_at |
quotes | Project quotes | project_id, created_by, total, line_items (JSONB) |
User roles
| Role | Can do |
|---|---|
admin | Everything — manage users, edit all data, reveal credentials |
project_manager | Edit projects, tasks, permits, notes |
coordinator | Update task statuses, add notes |
viewer | Read-only — Checkers corporate accounts |
Task statuses
| URL | Who | What |
|---|---|---|
/ | All internal users | Portfolio dashboard — all projects |
/project.html?id=X | All internal users | Project detail — tasks, notes, contacts |
/board.html | All internal users | Swimlane task board |
/quote.html | Admin, PM | Quoting tool |
/admin | Admin only | User management, site editing, templates |
/checkers | Checkers corporate | Read-only portfolio view |
/docs | All internal users | This manual |
BFAM team
| Name | Role | |
|---|---|---|
| Chad Buttrey | chadwick@bfambuilders.com | Admin |
| Ted Peterson | ted.peterson@bfambuilders.com | Admin |
| Jaci Mays | jaci.mays@bfambuilders.com | Admin |
| Joshua | joshua@bfambuilders.com | Project Manager |
| Dan Fenton | dan.fenton@bfambuilders.com | Coordinator |
| Ronald | ronald@bfambuilders.com | Viewer |
Checkers corporate
| Name | Access | |
|---|---|---|
| Kevin Sorensem | sorensenk@checkers.com | /checkers only (viewer) |
| Russell Bernstine | bernstiner@checkers.com | /checkers only (viewer) |
New project workflow
Automated workflows (Phantom)
| Trigger | Action |
|---|---|
| Every hour | Smartsheet sync — pulls construction dates from Checkers |
| Monday 7am Chicago | Weekly blocker report emailed to team |
| Daily 8am Chicago | Escalation — Teams ping for tasks blocked 3+ days |
| Task → Blocked | Immediate Teams notification |
| All permits issued | Teams notification to #construction-handoff |
The main view at / shows all active projects at a glance.
| Element | Description |
|---|---|
| Summary cards | Total projects, permits complete, in progress, mural pending |
| Filter buttons | All / Rere only / Remodel only / Complete / In progress |
| Progress bars | % of tasks complete per permit track |
| Status badges | Green=complete, Blue=in progress, Amber=ext blocked, Red=blocked, Gray=not started |
| + New project | Opens new project modal |
| Board link | Navigates to swimlane board |
| Docs link | Opens this manual |
| Show archived | Toggle archived projects |
| Dark mode | Sun/moon toggle — persists across all pages |
| Sign out | Signs out of Microsoft account |
Project detail page
| Panel | What you can do |
|---|---|
| Project header | See name, type, status, address. Click coordinator to assign. |
| Permit tracks | Collapsible checklists. Click status dropdown to update. Hover task for × remove. Click permit number to edit. |
| + Add task | Add ad hoc tasks below each permit track. |
| Activity log | All notes newest-first. Add note at bottom. |
| AHJ & Contacts | Jurisdiction contacts. + Add contact to add new ones. |
| Quotes | Saved quotes with date and total. + New quote to create one. |
| Archive button | Next to status badge. Confirms before archiving. |
Archiving vs deleting
Projects are never hard-deleted. Archive hides them from the dashboard but preserves all data. Toggle "Show archived" to restore. Use the Unarchive button on an archived project to make it active again.
Building permit — 14 tasks
| # | Task |
|---|---|
| 1 | Identify AHJ + GIS lookup |
| 2 | Look up requirements on city/county website |
| 3 | Check for online portal, create account if available |
| 4 | Submit via email/mail if no portal |
| 5 | Discuss registration, plan submittal, additional requirements with AHJ |
| 6 | Pull all required submittals and workflow |
| 7 | Request required docs (insurance cert, bond, tax office, NOC, LOA) |
| 8 | Complete contractor registration |
| 9 | Submit registration (license, COI, BTR, bond) |
| 10 | Coordinate sub-contractor registration |
| 11 | Complete and submit permit application |
| 12 | Coordinate with electrical and other sub trades |
| 13 | Complete and hold all submission documents |
| 14 | Pay fees and respond to all plan review comments |
The mural permit follows a decision tree — options are tried in order, stopping when one is approved. Locked options unlock automatically when the previous is rejected.
| Option | Description | Unlocks when |
|---|---|---|
| 1 | Mural on both sides | Always available first |
| 2 | Mural on one side | Option 1 rejected |
| 3 | Chevron painted | Option 2 rejected |
| 4 | Parallelogram painted | Option 3 rejected |
The board at /board.html shows all actionable tasks across all projects in five columns: Not started, In progress, Ext. blocked, Blocked, Complete.
- Filter by person using the dropdown — shows one coordinator's full workload
- Filter by project type (Rere/Remodel)
- Locked and N/A tasks are hidden — only actionable tasks shown
- Click any card to open the project detail page
- Overdue tasks show in red
The quoting tool at /quote.html replaces the manual process of reformatting IAM quotes into BFAM format.
Creating a quote
Saved quotes appear in the Quotes panel on the project detail page. Click any saved quote to reopen and edit it.
Checkers corporate contacts access a read-only view at /checkers. They sign in with their existing Checkers Microsoft accounts.
Visible to Checkers
- All project names and store numbers
- Permit status per project
- Mural status
- Construction scheduled start date
- Overall progress bar
Hidden from Checkers
- Internal notes and activity log
- Portal credentials
- AHJ contact details
- Task-level detail
- Internal team assignments
Admin page at /admin — accessible to Admin role only.
Users section
- Lists all users with name, email, role, and status
- Change role via dropdown — saves immediately
- Deactivate blocks login without deleting data
- Delete permanently removes the user and their allowlist entry
- Add user form creates DB record and adds to allowlist
- You cannot deactivate or delete yourself
Sites section
Click any field to edit inline — address, jurisdiction, portal URL, portal username. Changes save on Enter or blur.
Templates section
View the JSON task templates that define permitting checklists. Read-only in the UI. To modify templates, edit the JSON files in templates/ on the server.
sentinel/users.json manually on the server, always validate it before restarting Ghost: python3 -c "from sentinel.middleware import validate_users_json; validate_users_json()"Adding portal passwords to Key Vault
Infrastructure
| Service | Details | Cost/mo |
|---|---|---|
| Azure VM | fulcrum-vm-01, Standard_F1als_v7, Ubuntu 24.04 | ~$44 |
| PostgreSQL | Local on VM (not managed service) | $0 |
| SSL | Let's Encrypt via Certbot — auto-renews | $0 |
| DNS | bfam-fulcrum.centralus.cloudapp.azure.com | $0 |
| Total | ~$44/mo |
Deploy an update
Useful commands on the VM
Environment variables
All config lives in ~/fulcrum/.env on the Azure VM. Never commit this file. Key variables:
Repository
github.com/tedbp19/fulcrum — private. Main branch is production.
Local development
APP_ENV=development and comment out AZURE_TENANT_ID in .env to enable the auth bypass. Never deploy with these settings.Database migrations
create_type=False issue — autogenerate doesn't handle shared enum types correctly. See existing migrations for the pattern.Adding a permit template
Drop a new JSON file in templates/ following the existing format. Run scripts/migrate/04_seed_tasks.py to instantiate tasks for existing projects.