Construction management SaaS, own product
Obly
A construction management SaaS in production, used on the web and through the iOS app downloaded from the App Store. A NestJS API over PostgreSQL serves a Next.js web app and an Expo mobile app, sold by subscription in three plans and built spec first: the product intent lives in a documentation repository that precedes the code.
- Role
- Sole authorship: product, architecture and engineering across six repositories.
- Period
- 2026 to present
- Status
- In production, on the web and on the App Store

What the system does
- A daily log captured on site, with photos taken on the spot and document scanning through the camera.
- Per-project finance: budget by stage, expenses, supplier quotes and planned against spent.
- Scheduling with a work breakdown structure, assisted setup and MS Project XML import.
- A document library at the account level, holding designs, contracts, invoices and permits.
- Floor-plan reading from PDF and budget import from spreadsheets, both through a language model, with mandatory review before anything is written.
- A voice assistant that classifies what was said and turns it into an entry.
- A construction report in PDF, assembled from what was already recorded.
- Subscriber teams and client access, with permissions by role.
- Subscription in three plans, with a fourteen-day trial and no card.
Architecture
- A NestJS API over PostgreSQL holds the business rules, across twenty-seven modules and seventy-seven migrations. The Next.js web app and the Expo app consume the same domain model.
- Isolation per contracting account: team, floor plans, storage and commercial rights live at the account level, not the user level. There is no separate account entity, the account is the owning user.
- Authentication by a Firebase token verified on the server in a route guard. The backend stores no password, session or refresh token.
- An entitlement engine on the server: a capability catalog, a per-plan template in a table, a capability guard on write routes and an atomic monthly reservation for the model import quota.
- Library files in S3-compatible storage on Cloudflare R2, with signed URLs for upload and download. PostgreSQL holds the object key, and reconciliation of abandoned uploads runs once a day.
- Floor plans in PDF rendered with mupdf and read by a Gemini model. The same provider serves budget import and the assistant's classifier, always with schema-validated output before anything is written.
- Schedule import from MS Project XML and from spreadsheets. Import is always a preview: nothing enters the domain before confirmation.
- Subscription billing with Stripe, with prices read from the provider and never copied into the database or the UI.
- CI against a real PostgreSQL on GitHub Actions, migrations applied before deploy, and the daily cleanup routine scheduled in the same place.
- A code-free documentation repository holds the product intent: a single PRD, one hundred and seventy-six business rules with a status across fifteen domains, six ADRs, feature specs with acceptance criteria, and two skills describing the change procedure.
Implementation details
- No price is written into the database or the UI: the catalog is read from the payment provider on every request.
- The billing webhook records the event before any mapping, and a partial unique index enforces one live subscription per account.
- The mobile app does not sell: billing happens on the web, and the app only reads the entitlement in force.
Technologies
- TypeScript
- One language across the three application repositories.
- NestJS
- The API framework, with modules, guards and dependency injection.
- TypeORM
- ORM and the seventy-seven versioned migrations.
- PostgreSQL
- The product's single database.
- Next.js
- The authenticated web application.
- React Native e Expo
- The iOS and Android app, with file-based routing and delivery through EAS.
- Firebase Auth
- Identity on web and mobile, with the token verified on the server.
- Stripe
- Checkout, customer portal, subscription and webhook.
- Cloudflare R2
- Storage for photos, thumbnails and documents, with signed URLs.
- Gemini
- Floor-plan reading, budget import and the voice assistant's classifier.
- mupdf
- Rendering the PDF floor plan before the model reads it.
- exceljs e fast-xml-parser
- Reading the budget spreadsheet and the MS Project XML.
- Zod
- Validating model output before it becomes a write to the domain.
- TanStack Query
- Data caching and synchronization on the web.
- Tailwind CSS
- Styling for the web application.
- Jest, Supertest e Vitest
- Tests for the API, the web app and the mobile app.
- Swagger
- API documentation.
- Expo Push
- Notifications delivered by the API in batches, revoking invalid tokens.
- PostHog
- Product analytics in the mobile app.
- GitHub Actions
- CI against a real PostgreSQL and the daily cleanup routine.

The project schedule as a Gantt chart, grouped by stage, with bars for done, in progress and pending, and today's line. 
MS Project XML import under review: three stages and ten activities detected, with item-by-item selection before anything is created. 
Budget import through a language model, with the item list open for review before anything is written. 
Daily log in the mobile app, with a photo taken on site. 
The project document library, with folders for designs, contracts, invoices and permits. 
Cover of the construction report generated for the client.
Want to talk about architecture, technical decisions and shipping to production?
