2025–2026 · In production · Contract
BuildFlowCRM
Commercial real-estate CRM with maker-checker governance
Full-stack Engineer · sole builder
- Asset classes
- 5
- Approvals
- Maker-checker
- Data I/O
- Excel round-trip
- Stack
- MERN
The problem
A commercial real-estate brokerage was tracking properties, deals, and contacts across spreadsheets and disconnected tools. Five different asset classes — warehouses, corporate offices, coworking, retail/malls, and managed offices — each carry their own attributes, so a single flat 'property' table never fit. And with several agents editing shared records, the firm needed edits and deletions to be reviewable rather than silently overwritten — without blocking day-to-day work.
My approach
I built the CRM around two ideas. First, polymorphic entities: one base schema per concept (Projects, Inventory, Contacts) with Mongoose discriminators layering asset-class-specific fields on top — so a coworking listing carries seats and setup fees while a warehouse carries dock and area fields, all in one collection under shared validation. Second, a maker-checker workflow: an employee's update or delete doesn't apply directly — it creates a PendingAction routed to their manager for approval, while the source record is flagged as under-review so the UI reflects its pending state.
Architecture
A Node/Express + Mongoose 8 backend (ESM) is organized into routes → controllers → services → models. Discriminators (project_type / inventory_type / contact type) model the asset classes, while a single PendingAction collection uses a dynamic refPath to reference any entity — Lead, Contact, DeveloperCompany, Project, Inventory, or Land — capturing the requested diff as a Mixed payload and assigning it to the requester's boss. RBAC is two-tier (admin / employee) with an owner-boss hierarchy that governs assignment and record visibility. Auth is JWT over httpOnly cookies, hardened with helmet, a configurable CORS allowlist, express-rate-limit, and proxy-aware trust for Railway. Documents — profile photos, land papers, and project/inventory attachments — stream to Cloudflare R2 through the S3 SDK's multipart uploader behind Multer. A full Import/Export hub round-trips every entity through Excel (ExcelJS) with per-entity schemas, validation, and bulk post-import. Tested with Vitest + Supertest.
Highlights
- Polymorphic Projects/Inventory/Contacts via Mongoose discriminators — five commercial asset classes in one schema family.
- Maker-checker approval workflow: employee edits and deletes become PendingActions routed to a manager; records stay flagged under-review until approved.
- Dynamic refPath approvals — a single collection references any entity type (Lead, Contact, Developer, Project, Inventory, Land).
- Two-tier RBAC with a manager (boss) hierarchy driving assignment and record visibility.
- Excel import/export for every entity with per-schema validation and bulk post-import.
- Document management on Cloudflare R2 (S3-compatible) with multipart streaming uploads.
- Hardened API: JWT cookie auth, helmet, CORS allowlist, rate limiting, and proxy-aware trust for Railway.
Tech stack
Backend
Auth / Security
Storage / Docs
Frontend
Testing / Deploy